2011-03-31 74 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(); 
       } 
      } 
     } 
    } 
}