Могу ли я абстрагировать Entity Framework от моих сущностей? - PullRequest
9 голосов
/ 29 марта 2009

У меня есть Foo сущность в Entity Framework. Но я заставляю его наследовать от IFoo, чтобы моя бизнес-логика знала только IFoo - таким образом абстрагируясь от Entity Framework.

Проблема в том, что Foo имеет коллекцию Bar сущностей. И эта коллекция имеет тип EntityCollection<Bar>.

Если я помещу эту коллекцию в IFoo как есть, я сделаю IFoo зависимым от Entity Framework. Поэтому я подумал о том, чтобы указать его как ICollection<IBar>, но это не компилируется (естественно).

Единственное решение, которое я могу придумать, - это перейти к конкретной реализации Foo, сгенерированной конструктором Entity Framework, и изменить там коллекцию с EntityCollection<Bar> на ICollection<IBar>. Но я боюсь мысли о последствиях, которые это будет иметь для Entity Framework "за кулисами".

Можно ли как-нибудь определить IFoo и IBar независимо от Entity Framework, при этом сохраняя Foo и Bar в качестве сущностей EF, которые их реализуют? Имеют ли смысл IFoo и IBar, если я не могу достичь той независимости, к которой стремлюсь?

Ответы [ 5 ]

8 голосов
/ 29 марта 2009

Общая концепция, на которую вы ссылаетесь, - это «невежество в постоянстве» (PI), хотя это обычно относится непосредственно к самим сущностям, а не к коду, который потребляет сущности.

В любом случае Hibernate и NHibernate изначально поддерживают PI, но первоначальная версия Entity Framework от Microsoft - нет. MS зацепилась за это, и PI, вероятно, самая обсуждаемая особенность # 1 для следующей версии (когда бы то ни было).

Что касается того, что вы пытаетесь сделать с интерфейсами, нужно ли изменять коллекцию столбцов после ее получения? Если ответ «да», то нет простого ответа. Даже ковариация не может помочь вам, потому что ICollection<T> имеет метод Add.

Если коллекция доступна только для чтения, вы можете представить ее как IEnumerable<IBar>. Метод Enumerable.Cast делает это довольно удобным.

interface IFoo
{
    IEnumerable<IBar> Bars { get; }
}

partial class Foo : IFoo
{
    IEnumerable<IBar> IFoo.Bars
    {
        get { return Bars.Cast<IBar>(); }
    }
}

Кроме того, я знаю о по крайней мере одно усилие , чтобы сделать текущую версию EF поддерживающей невежество постоянства.

2 голосов
/ 02 мая 2009

Мы делаем то же самое для LINQ to SQL. Я решил проблему с коллекцией, написав класс, который упаковывает IList и приводит к нужному типу и обратно. Это выглядит примерно так:

public class ListWrapper<TSource, TTarget> : IList<TTarget>
    where TTarget : class
    where TSource : class, TTarget
{
    private IList<TSource> internalList;

    public ListWrapper(IList<TSource> internalList)
    {
        this.internalList = internalList;
    }

    public void Add(TTarget item)
    {
        internalList.Add((TSource)item);
    }

    public IEnumerator<TTarget> GetEnumerator()
    {
        return new EnumeratorWrapper<TSource, TTarget>(internalList.GetEnumerator());
    }

    // and all the other IList members
}

EnumeratorWrapper аналогично оборачивает IEnumerator и выполняет приведение. В частичных классах LINQ to SQL мы выставляем свойство следующим образом:

public IList<ICustomer> Foos
{
    get
    {
        return new ListWrapper<Foo, IFoo>(this.Foos_internal);
    }
}

Любые изменения в открытом списке будут выполняться во внутреннем EntitySet, поэтому они будут синхронизированы.

Это работает достаточно хорошо, но я чувствую, что весь этот подход доставляет больше хлопот, чем стоит, я большой фанат NHibernate и убежденный сторонник P.I. но мы приложили немало дополнительных усилий, чтобы сделать это, и не увидели никакого преимущества. Мы используем шаблон репозитория, чтобы абстрагироваться от фактического доступа к DataContext, который, я бы сказал, является ключевой частью отделения нас от LINQ to SQL.

2 голосов
/ 02 мая 2009

Я недавно написал всеобъемлющий пост об этом: Постоянное невежество в ADO.NET Entity Framework . Возможно, вы захотите взглянуть на EFPocoAdapter. Это делает именно это, и в конечном итоге он устареет в EF v2.

Что бы это ни стоило, я использую EFPocoAdapater, и он хорошо работает для меня.

2 голосов
/ 29 марта 2009

Используйте частичный класс для отделения вашей логики и правил от автоматически сгенерированных объектов EF. В приведенном ниже примере класс FooEntityObject разделен на две части с использованием ключевого слова частичного. Я использовал эту технику раньше с EF и LINQ to SQL. Частичные классы могут храниться в отдельных файлах, поэтому, если вы заново создадите объект EF, ваш пользовательский код не будет перезаписан.

interface IFoo
{
    public ICollection<IBar> GetBars();
}

public partial class FooEntityObject : IFoo
{
    public ICollection<IBar> GetBars()
    {
        // convert EntityCollection<Bar> into ICollection<IBar> here
    }
}


public partial class FooEntityObject
{
    EntityCollection<Bar> Bars{get;set;}
}
2 голосов
/ 29 марта 2009

Я разработчик Java, поэтому я не могу комментировать какие-либо права на Entity Framework. Я могу вам сказать, что решения ORM, такие как Hibernate, позволяют сохранять постоянство POJO, не прибегая к общим абстрактным классам, интерфейсам или модификации байтового кода. Он обрабатывает отношения, такие как 1: m, которые вы цитируете для Foo и Bar, без необходимости использовать специальные классы коллекции.

Специальный соус выводится в картографическую конфигурацию и сам Hibernate.

Немного, что я прочитал о Entity Framework, говорит о том, что это решение ORM с той же целью: постоянство POCO. Я не видел упоминаний об интерфейсах. Я не вижу необходимости в них из вашего примера, потому что он слишком абстрактный.

Я предполагаю, что можно получить эту независимость между бизнес-объектами и уровнем персистентности, не прибегая к этим интерфейсам, потому что я знаю, что это делает Hibernate. Я бы сказал, что решение Spring JDBC также выполняет это, потому что нет необходимости в общих интерфейсах. Они используют конструкцию RowMapper для передачи данных из запроса в объект.

Хотелось бы, чтобы я точно советовал вам, как это сделать с помощью Entity Framework, но, может быть, вы покоряетесь, зная, что это можно сделать.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...