Каковы преимущества универсального шаблона репозитория + шаблона UOW с ORM-подобной Entity Framework

Давайте начнем с двух цитат, суммирующих эту проблему: "Заключение DbContext - это утечка абстракции. В любом случае, вы окажетесь в некоторой зависимости от EF на уровне сервисов / контроллеров". цитата ref И вторая цитата:

"Класс DbContext

Представляет комбинацию шаблонов Unit-Of-Work и Repository и позволяет запрашивать базу данных и группировать изменения, которые затем будут записаны обратно в хранилище как единое целое. " MSDN

Пожалуйста, не говорите, что шаблон репозитория позволяет вам просто поменять базу данных, это не так. Кто-нибудь когда-нибудь делал это со зрелым приложением? Пожалуйста, также не отвечайте, что шаблон Repository не должен раскрывать IQueryable, я думаю, это просто еще один способ сказать, что вы не доверяете людям, с которыми работаете.

Я всецело за инкапсуляцию, покрытие кода / тестируемость, но так как этот популярный шаблон репо для EF предоставляет IQueryable, больше нет необходимости в таком шаблоне:

   public interface IRepository<T> where T : class
    {
    IQueryable<T> GetAll();
    T GetById(int id);
    IEnumerable<T> Get(Expression<Func<T, bool>> filter = null,Func<IQueryable<T>,IOrderedQueryable<T>> orderBy = null, string includeProperties = "");
    void Add(T entity);
    void Update(T entity);
    void Delete(T entity);
    void Delete(int id);
}

Единственными преимуществами шаблона репозитория в сочетании с шаблоном UOW являются: 1. Простое включение шаблона внедрения зависимостей для повышения тестируемости / охвата кода. 2. Инкапсулируйте сложность, которая существует при внешней интеграции (вызовы веб-служб для различных поставщиков, веб-интерфейс, базы данных)., так далее..)

Так какую инкапсуляцию я получаю, чего не получаю, используя класс MyDbContext: DbContext? Мой ORM - это абстракция. Конечно, я получаю некоторую однородность контроллеров с UOW работы и общими запросами, такими как Add и Delete, но это действительно стоит затраченных усилий. Разве я не могу просто доверять своим разработчикам, чтобы они были едины, и когда они делают это немного по-своему, просто не забывайте об этом. И так как контроллер может написать любой запрос, который он хочет, разве это не бросает вызов модульному тестированию? И (даже большие заглавные буквы), если у меня есть сторонний API для вызова, я могу сделать это доступным в классе MyDbContext для контроллеров, так что это выглядит как очередной вызов данных для контроллера.

Я снова говорю, почему бы не использовать ORM напрямую, это абстракция данных!

Вот несколько аргументов против шаблона репозитория:

http://ayende.com/blog/4784/architecting-in-the-pit-of-doom-the-evils-of-the-repository-abstraction-layer

http://ayende.com/blog/3955/repository-is-the-new-singleton

http://lostechies.com/jimmybogard/2012/09/20/limiting-your-abstractions/

http://lostechies.com/jimmybogard/2012/10/08/favor-query-objects-over-repositories/

Вот правильный аргумент для шаблона репозитория (хотя и недостаточно убедительный): http://www.sapiensworks.com/blog/post/2012/10/10/Do-We-Need-The-Repository-Pattern.aspx

2 ответа

Решение

Я думаю, что сойду с ума, если увижу, что Айенде отправит сообщение еще раз. Давайте рассмотрим каждую вещь медленно:

  1. Универсальный репозиторий имеет ограниченную применимость. Лично я использую его ТОЛЬКО для репозиториев доменов и ТОЛЬКО когда храню агрегатные корни в сериализованной форме. Для всего остального (читай: просмотр моделей, отчетов) у меня был бы репозиторий, разработанный для нужд слоя, запрашивающего эти модели.

  2. IQueryable в значительной степени построитель запросов. Вы не говорите хранилищу, как создать что-то (IQUeryable), вы просто спрашиваете что-то из этого. Если вы используете IQueryable, вы уже выполняете часть работы хранилища (нарушая SRP более высокого уровня). Также предоставление IQueryable означает, что верхний уровень ДОЛЖЕН знать о документах / сущностях, используемых для создания запроса. Если ваш начальник решит, что отныне вы будете получать данные из веб-службы, что бы вы сделали со всеми этими объектами IQueryable и ORM, разбросанными повсюду? Или СУБД слишком медленная, так что давайте использовать Document Db? Да, это может поддержать linq, но вы уверены, что у вас будут определены те же сущности?

  3. Не доверяйте своим разработчикам. Доверьтесь правильной архитектуре, в которой вы не смешиваете обязанности уровня и где соблюдается SRP (принцип единой ответственности). Если вы разрабатываете, скажем, просмотр моделей в соответствии с тем, как данные хранятся в БД, а не с тем, что вам нужно в представлении, у вас есть проблема тесной связи.

  4. Причина, по которой не используется репо, потому что вам не нужно менять ORM или технологию хранения, ИМХО похожа на причину: зачем использовать DI-контейнер или интерфейсы, есть небольшая вероятность, что эти классы изменится, и мы можем сделать вручную инъекция в любом случае.

  5. Использование репозитория означает, что вам не нужно заботиться о том, как и откуда ваши модели извлекаются. Хранилище предоставляет семантику, дружественную бизнесу (GetTopSellingProducts). С помощью orm вы должны создать запрос (все любят выполнять объединения и подзапросы в linq), знать о сущностях, делать прогнозы и т. Д. Почему высший уровень должен заботиться об этих деталях? Это принцип "спрашивай, не говори как" (j/k)

В конце концов, все дело в поддерживаемом коде, я хочу, чтобы мой код был легко понят.

Я снова говорю, почему бы не использовать ORM напрямую, это абстракция данных!

Это абстракция данных, а не абстракция данных.

Речь идет об абстрагировании вашего ORM, если вам нужно его отключить. Не о том, что может предложить общий репозиторий напрямую через DbContext. Если вам нужно было отключить EF и DbContext, и он был сильно связан, вам нужно будет отредактировать все разделы вашего кода, использующие DbContext, или вы будете вынуждены реализовать интерфейс DbContext на любом ORM, на который вы переключаетесь.

Говоря, что я думаю, что вероятность переключения ORM в большинстве приложений невелика, а удобство использования DbContext напрямую перевешивает риск соединения с EF. Тем не менее, я до сих пор понимаю, почему некоторые захотят сделать это в зависимости от требований приложения и срока службы.

Другие вопросы по тегам