2011-03-31 60 views

回答

9

这取决于您如何期望在应用程序中使用EAV。 EF可用于映射:

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; } 
} 

这是什么可以被持久化以及Linq-to-entities可以查询什么。现在,您可以通过定义帮助属性来使您的实体可用(只能在您的应用程序中使用,而不能通过持久性或查询)。

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(); 
     } 
    } 
} 

这是不是很好,因为转换和收集搜索的:可选属性必须在集合中还访问 - 这些辅助属性只能用于众所周知的属性,这将永远存在实体类型使用。如果您多次访问数据,它们将被多次执行。

我没有尝试过,但我认为这可以通过实现每个实体类似的界面来避免:

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(); 
} 

现在,您将处理在ObjectContextObjectMaterializedSavingChanges事件。在第一个处理程序中,如果物化对象在第二个处理程序中执行IEavEntity,则将执行Initialize,您将迭代ObjectStateManager以获取实施IEavEntity的所有更新或插入实体,并执行Finalize。例如:

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(); 
       } 
      } 
     } 
    } 
}