2011-03-31 24 views
6

¿Puede EntityFramework admitir un modelo de EAV? ¿Es esto un escenario factible o una pesadilla? Quiero usar un modelo de EAV para un sistema, y ​​me gustaría abrazar a EF si es posible, pero me preocupa que estas dos filosofías estén en conflicto.¿Puede EntityFramework admitir un modelo de EAV?

Respuesta

9

Depende de cómo esperas usar EAV en la aplicación. EF se puede utilizar para mapear esto:

public partial class Entity 
{ 
    // Key 
    public virtual int Id { get; set; } 
    // Other common properties 

    // Attributes 
    public virtual ICollection<EavAttriubte> Attributes { get; set; } 
} 

// The simplest implementation 
public class EavAttribute 
{ 
    // Key 
    public virtual int Id { get; set; } 
    public virtual string Name { get; set; } 
    public virtual string Value { get; set; } 
} 

Esto es lo que puede ser persistido y lo que puede ser consultada por entidades LINQ a. Ahora puede hacer que su entidad se pueda utilizar definiendo propiedades de ayuda (se puede usar solo en su aplicación, pero no por persistencia o consultas). Estas propiedades auxiliares se pueden utilizar solamente para los atributos conocidos que siempre existe para el tipo de entidad - atributos opcionales deben ser todavía accesibles en la colección:

public partial class Entity 
{ 
    // Just example without error handling 
    public decimal Price 
    { 
     get 
     { 
      return Int32.Parse(Attributes.Single(a => a.Name == "Price")); 
     } 
     set 
     { 
      Attributes.Single(a => a.Name == "Price").Value = value.ToString(); 
     } 
    } 
} 

Esto no es muy agradable debido a las conversiones y la búsqueda de la colección. Si accede a los datos varias veces, se ejecutarán varias veces.

yo no probado, pero creo que esto puede evitarse mediante la implementación de una interfaz similar por cada entidad:

public interface IEavEntity 
{ 
    // loads attribute values from Attributes collection to local fields 
    // => conversion will be done only once 
    void Initialize(); 
    // saves local values back to Attributes collection 
    void Finalize(); 
} 

Ahora va a manejar ObjectMaterialized y SavingChanges eventos en ObjectContext. En el primer controlador, ejecutará Initialize si el objeto materializado implementa IEavEntity en el segundo controlador iterará ObjectStateManager para obtener todas las entidades actualizadas o insertadas que implementen IEavEntity y ejecutará Finalize. Algo como:

public void OnMaterialized(object sender, ObjectMaterializedEventArgs e) 
{ 
    var entity = e.Entity as IEavEntity; 
    if (entity != null) 
    { 
     entity.Initialize(); 
    } 
} 

public void SavingChanges(object sender, EventArgs e) 
{ 
    var context = sender as ObjectContext; 
    if (context != null) 
    { 
     foreach (var entry in context.ObjectStateManager.GetObjectStateEntries(
      EntityState.Added | EntityState.Modified)) 
     { 
      if (!entry.IsRelationship) 
      { 
       var entity = entry.Entity as IEavEntity; 
       if (entity != null) 
       { 
        entity.Finalize(); 
       } 
      } 
     } 
    } 
} 
Cuestiones relacionadas