EntityFramework可以支持EAV模型吗?这是一个可行的场景,还是一场噩梦?我想在系统中使用EAV模型,如果可能的话我想拥抱EF,但我担心这两种哲学是冲突的。
答案 0 :(得分: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();
}
现在,您将处理ObjectMaterialized
上的SavingChanges
和ObjectContext
个事件。在第一个处理程序中,如果物化对象在第二个处理程序中实现Initialize
,您将执行IEavEntity
,您将迭代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();
}
}
}
}
}