Зависит от того, как вы ожидаете использовать 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-entity. Теперь вы можете сделать вашу сущность пригодной для использования, определив вспомогательные свойства (может использоваться только в вашем приложении, но не может использоваться для сохранения или запроса). Эти вспомогательные свойства могут использоваться только для общеизвестных атрибутов, которые всегда будут существовать для типа сущности - необязательные атрибуты должны быть все еще доступны в коллекции:
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();
}
}
}
}
}