Может ли EntityFramework поддерживать модель EAV? - PullRequest
6 голосов
/ 31 марта 2011

Может ли EntityFramework поддерживать модель EAV?Это выполнимый сценарий или кошмар?Я хочу использовать модель EAV для системы, и я хотел бы использовать EF, если это возможно, но я обеспокоен тем, что эти две философии находятся в конфликте.

1 Ответ

9 голосов
/ 31 марта 2011

Зависит от того, как вы ожидаете использовать 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();
                }
            }
        }
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...