НЕ используя шаблон репозитория, используйте ORM as is (EF)

Я всегда использовал шаблон репозитория, но для моего последнего проекта я хотел посмотреть, могу ли я улучшить его использование и мою реализацию "Единицы работы". Чем больше я начал копать, я начал задавать себе вопрос: "Нужно ли мне это действительно?"

Теперь все начинается с нескольких комментариев на Stackoverflow со следом за сообщением Айенде Рахиен в его блоге с двумя конкретными,

Об этом, вероятно, можно было бы говорить вечно и всегда, и это зависит от разных приложений. Что мне нравится,

  • будет ли этот подход подходящим для проекта Entity Framework?
  • Используя этот подход, бизнес-логика все еще идет на уровне службы или методы расширения (как объясняется ниже, я знаю, метод расширения использует сеанс NHib)?

Это легко сделать с помощью методов расширения. Чистое, простое и многоразовое.

public static IEnumerable GetAll(
    this ISession instance, Expression<Func<T, bool>> where) where T : class
{
    return instance.QueryOver().Where(where).List();
}

Используя этот подход и Ninject как DI, мне нужно сделать интерфейс Context a и ввести его в мои контроллеры?

Ответ 1

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

Кодирование исключения

Вы кодируете для 1% вероятность того, что ваша база данных изменится с одной технологии на другую? Если вы думаете о своем будущем в будущем в бизнесе и говорите "да", то возможность: а) у них должно быть много денег, чтобы позволить перейти на другую технологию БД или б) вы выбираете технологию БД для развлечения или с ) что-то пошло ужасно неправильно с первой технологией, которую вы решили использовать.

Зачем выбрасывать богатый синтаксис LINQ?

LINQ и EF были разработаны таким образом, чтобы вы могли аккуратно делиться с ними, чтобы читать и пересекать графы объектов. Создание и поддержка репозитория, который может дать вам такую ​​же гибкость, чтобы сделать это, является чудовищной задачей. По моему опыту в любое время, когда я создал репозиторий, у меня ВСЕГДА произошла утечка бизнес-логики в уровень репозитория, чтобы сделать запросы более результативными - ant и/или уменьшить количество обращений к базы данных.

Я не хочу создавать метод для каждой отдельной перестановки запроса, который я должен написать. Я мог бы также написать хранимые процедуры. Я не хочу GetOrder, GetOrderWithOrderItem, GetOrderWithOrderItemWithOrderActivity, GetOrderByUserId и т.д. Я просто хочу получить основную сущность и пройти и включить граф объектов так, как вам нравится.

Большинство примеров репозиториев - дерьмо

Если вы не разрабатываете что-то ДЕЙСТВИТЕЛЬНО голые кости, такие как блог, или что-то, что ваши запросы никогда не будут такими же простыми, как 90% примеров, которые вы найдете в Интернете, окружающих шаблон репозитория. Я не могу подчеркнуть это достаточно! Это то, что нужно проползать через грязь, чтобы понять. Всегда будет один запрос, который разбивает ваш идеально продуманный репозиторий/решение, которое вы создали, и его не до тех пор, пока вы не догадаетесь о себе и о техническом долге/эрозии.

Не unit test me bro

Но как насчет модульного тестирования, если у меня нет репозитория? Как я буду издеваться? Просто вы этого не делаете. Давайте посмотрим на это с обоих углов:

Нет репозитория. Вы можете издеваться над DbContext с помощью IDbContext или некоторых других трюков, но тогда вы действительно тестируете LINQ для объектов, а не LINQ to Entities, потому что запрос определяется во время выполнения... ОК, так что это не хорошо! Итак, теперь до теста интеграции, чтобы покрыть это.

С репозиторием - теперь вы можете смешать свои репозитории и unit test слой между ними. Отлично? На самом деле не так... В приведенных выше случаях, когда вам нужно протекать логику в слое репозитория, чтобы сделать запросы более результативными - ant и/или меньше попаданий в базу данных, как ваши обходные тесты могут покрыть это? Теперь он находится на уровне репо, и вы не хотите правильно тестировать IQueryable? Также давайте честно сказать, что ваши модульные тесты не будут охватывать запросы, у которых есть 20 строк .Where() и .Include() связка отношений и снова удаляет базу данных, чтобы делать все это, бла, бла, бла так или иначе, потому что запрос генерируется во время выполнения. Кроме того, поскольку вы создали хранилище, чтобы сохранить приоритет на верхних уровнях невежественным, если теперь вы хотите изменить технологию баз данных, извините, что ваши юнит-тесты вызывающе не гарантируют одинаковые результаты во время выполнения, вернутся к интеграционным тестам. Таким образом, весь смысл хранилища кажется странным.

2 цента

Мы уже теряем много функциональности и синтаксиса при использовании EF поверх простых хранимых процедур (объемные вставки, массовые удаления, CTE и т.д.), но я также код на С#, поэтому мне не нужно вводить двоичный код. Мы используем EF, поэтому у нас есть возможность использовать разные провайдеры и работать с объектными графами в хорошо связанном ключе среди многих вещей. Определенные абстракции полезны, а некоторые нет.

Я надеюсь, что это поможет кому-то в интернетах где-то...

Ответ 2

Шаблон репозитория - абстракция. Цель состоит в том, чтобы уменьшить сложность и сделать остальной код неустойчивым. В качестве бонуса вы можете писать модульные тесты вместо тестов интеграции.

Проблема заключается в том, что многие разработчики не понимают цели шаблонов и создают репозитории, которые вызывают утечку специфической информации до вызывающего абонента (обычно путем раскрытия IQueryable<T>). Поступая таким образом, они не получают никакой выгоды от использования OR/M напрямую.

Обновить для ответа на другой ответ

Кодирование исключения

Использование репозиториев заключается не в возможности переключения технологии сохранения (т.е. изменения базы данных или использования webservice и т.д.). Это о том, чтобы отделить бизнес-логику от настойчивости, чтобы уменьшить сложность и взаимосвязь.

Модульные тесты и тесты интеграции

Вы не пишете модульные тесты для репозиториев. период.

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

Что касается запросов. Если вы используете LINQ, вам также необходимо убедиться, что ваши запросы работают так же, как и с репозиториями. и это делается с помощью тестов интеграции.

Разница в том, что если вы не смешивали свой бизнес с операторами LINQ, вы можете быть на 100% уверены, что это ваш код персистентности, который не работает, а не что-то еще.

Если вы проанализируете свои тесты, вы также увидите, что они намного чище, если у вас нет смешанных проблем (например, LINQ + Business logic)

Примеры репозитория

Большинство примеров - это дерьмо. Это очень верно. Однако, если у вас есть какой-либо шаблон дизайна, вы найдете множество дерьмовых примеров. Это не повод избежать использования шаблона.

Создание правильной реализации репозитория очень просто. Фактически, вы должны следовать только одному правилу:

Не добавляйте ничего в класс репозитория до самого момента, когда вам это нужно

Многие кодеры ленивы и пытаются создать общий репозиторий и использовать базовый класс с множеством методов, которые им могут . YAGNI. Вы пишете класс хранилища один раз и сохраняете его до тех пор, пока приложение живет (может быть лет). Зачем трахать его, ленив. Держите его в чистоте без наследования базового класса. Это облегчит чтение и поддержку.

(Вышеприведенное утверждение является ориентиром, а не законом. Базовый класс может быть очень мотивирован. Подумайте, прежде чем добавлять его, чтобы добавить его по правильным причинам)

Старый материал

Вывод:

Если вы не против иметь инструкции LINQ в своем бизнес-коде и не заботитесь об модульных тестах, я не вижу причин не использовать Entity Framework напрямую.

Обновление

Я писал как о шаблоне репозитория, так и о том, что на самом деле означает "абстракция": http://blog.gauffin.org/2013/01/repository-pattern-done-right/

Обновление 2

Для одного типа сущности с 20 + полями, как вы будете создавать метод запроса для поддержки любой комбинации перестановок? Вы не хотите ограничивать поиск только по имени, как насчет поиска с навигационными свойствами, перечислить все заказы с элементом с конкретным ценовым кодом, 3 уровня поиска навигационной собственности. Вся причина IQueryable была изобретена в том, чтобы иметь возможность составлять любую комбинацию поиска по базе данных. Все выглядит великолепно в теории, но пользователь нуждается в победах над теорией.

Снова: объект с 20 + полями некорректно моделируется. Это объект БОГ. Сломай.

Я не утверждаю, что IQueryable не был создан для запроса. Я говорю, что это неправильно для слоя абстракции, такого как шаблон репозитория, поскольку он негерметичен. Нет ни одного 100% -ного провайдера LINQ To Sql (например, EF).

Все они имеют конкретные реализации, такие как использование нетерпеливой/ленивой загрузки или инструкции SQL "IN". Выставление IQueryable в репозитории заставляет пользователя знать все эти вещи. Таким образом, вся попытка абстрагировать источник данных - это полный сбой. Вы просто добавляете сложность, не получая никакой выгоды от использования OR/M напрямую.

Либо правильно создавайте шаблон хранилища, либо просто не используйте его вообще.

(Если вы действительно хотите обрабатывать большие объекты, вы можете комбинировать шаблон репозитория с Спецификацией. Это дает вам полную абстракцию, которая также можно проверить.)

Ответ 3

IMO как абстракция Repository, так и абстракция UnitOfWork имеют очень ценное место в любой значимой разработке. Люди будут обсуждать детали реализации, но так же, как есть много способов скинуть кошку, существует множество способов реализации абстракции.

Ваш вопрос специально использовать или не использовать и почему.

Как вы, без сомнения, поняли, что у вас уже есть оба шаблона, встроенные в Entity Framework, DbContext - это UnitOfWork и DbSet - это < код > Repositoryкод > . Обычно вам не нужно unit test UnitOfWork или Репозиторий, поскольку они просто облегчают между вашими классами и базовыми реализациями доступа к данным. То, что вам нужно будет делать, снова и снова, издевается над этими двумя абстракциями, когда модуль тестирует логику ваших услуг.

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

Итак, второстепенным моментом является то, что , имеющее собственную абстракцию для UnitOfWork и Repository, дает вам максимальный контроль и гибкость при издевательском тестировании вашего устройства.

Все очень хорошо, но для меня реальная сила этих абстракций заключается в том, что они обеспечивают простой способ применения методов аспектно ориентированного программирования и придерживаются принципов SOLID.

Итак, у вас есть ваш IRepository:

  открытый интерфейс IRepository <T>   где T: класс
{   T Добавить (объект T);   void Удалить (объект T);   IQueryable < Т > AsQueryable();
}
Код>

И его реализация:

  public class Repository <T>: IRepository <T>   где T: класс
{   private readonly IDbSet <T> _dbSet;   публичный репозиторий (контекст PPContext)   {       _dbSet = context.Set <T>();   }
   public T Добавить (объект T)   {       return _dbSet.Add(entity);   }
   public void Удалить (объект T)   {       _dbSet.Remove(юридическое лицо);   }
   открытый IQueryable <T> AsQueryable()   {       return _dbSet.AsQueryable();   }
}
Код>

Пока что ничего необычного, но теперь мы хотим добавить некоторые протоколирования - легко с помощью журнала Decorator.

  открытый класс RepositoryLoggerDecorator <T>: IRepository <T>   где T: класс
{   Logger logger = LogManager.GetCurrentClassLogger();   private readonly IRepository <T> _украшен;   public RepositoryLoggerDecorator (IRepository <T>)   {       _decorated = оформлено;   }
   public T Добавить (объект T)   {       logger.Log(LogLevel.Debug,() = > DateTime.Now.ToLongTimeString());       T добавил = _decorated.Add(сущность);       logger.Log(LogLevel.Debug,() = > DateTime.Now.ToLongTimeString());       возврат добавлен;   }
   public void Удалить (объект T)   {       logger.Log(LogLevel.Debug,() = > DateTime.Now.ToLongTimeString());       _decorated.Delete(юридическое лицо);       logger.Log(LogLevel.Debug,() = > DateTime.Now.ToLongTimeString());   }
   открытый IQueryable <T> AsQueryable()   {       return _decorated.AsQueryable();   }
}
Код>

Все сделано и без изменения нашего существующего кода. Существует множество других проблем, связанных с перекрестными перекрестными связями, которые мы можем добавить: обработка исключений, кэширование данных, валидация данных или что-то еще, и на протяжении всего нашего процесса проектирования и сборки самая ценная вещь, которая у нас есть, что позволяет нам добавлять простые функции, не меняя наш существующий код - это наш IRepository абстракция.

Теперь, много раз я видел этот вопрос в StackOverflow - "как заставить Entity Framework работать в среде с несколькими арендаторами?".

https://stackoverflow.com/search?q=%5Bentity-framework%5D + + мульти арендатор

Если у вас есть абстракция Repository, тогда ответ "легко добавить декоратора"

  public class RepositoryTennantFilterDecorator <T>: IRepository <T>   где T: класс
{   //public  для примера unit test  public readonly IRepository <T> _украшен;   public RepositoryTennantFilterDecorator (IRepository <T>)   {       _decorated = оформлено;   }
   public T Добавить (объект T)   {       return _decorated.Add(entity);   }
   public void Удалить (объект T)   {       _decorated.Delete(юридическое лицо);   }
   открытый IQueryable <T> AsQueryable()   {       return _decorated.AsQueryable(). Где (o = > true);   }
}
Код>

IMO, вы всегда должны размещать простую абстракцию над любым сторонним компонентом, на который будут ссылаться более чем в нескольких местах. С этой точки зрения ORM является идеальным кандидатом, поскольку он упоминается во многих наших кодах.

Ответ, который обычно приходит на ум, когда кто-то говорит "почему я должен иметь абстракцию (например, <репозиторий ) над той или иной сторонней библиотекой" есть ", почему бы вам?"

P.S. Декораторы чрезвычайно просты в применении с использованием контейнера IoC, например SimpleInjector.

<Предварительно > <код > [TestFixture] публичный класс IRepositoryTesting {   [Контрольная работа]   public void IRepository_ContainerRegisteredWithTwoDecorators_ReturnsDecoratedRepository()   {       Контейнер контейнера = новый контейнер();       container.RegisterLifetimeScope <PPContext> ();       container.RegisterOpenGeneric(           TypeOf (IRepository < & Н),           TypeOf (Repository < > ));       container.RegisterDecorator(           TypeOf (IRepository < & Н),           TypeOf (RepositoryLoggerDecorator < > ));       container.RegisterDecorator(           TypeOf (IRepository < & Н),           TypeOf (RepositoryTennantFilterDecorator < > ));       container.Verify();       используя (container.BeginLifetimeScope())       {           var result = container.GetInstance < IRepository <image> ();           Assert.That(               результат,               Is.InstanceOf(TypeOf (RepositoryTennantFilterDecorator < Изображение > )));           Assert.That(               (результат как RepositoryTennantFilterDecorator <image> )._ украшен,               Is.InstanceOf(TypeOf (RepositoryLoggerDecorator < Изображение > )));       }   } } Код >

Ответ 4

Прежде всего, как было предложено некоторым ответом, EF сам по себе является шаблоном репозитория, нет необходимости создавать дополнительную абстракцию только для того, чтобы называть его репозиторием.

Mockable Repository для модульных тестов, действительно ли он нужен?

Мы передаем EF для тестирования БД в модульных тестах, чтобы проверить нашу бизнес-логику прямо на тестовой БД SQL. Я не вижу никакой пользы от макета какого-либо шаблона репозитория. Что действительно не так делает модульные тесты против тестовой базы данных? Поскольку это массовые операции невозможны, и мы заканчиваем тем, что пишем исходный SQL. SQLite в памяти - идеальный кандидат для проведения модульных тестов с реальной базой данных.

Ненужная абстракция

Вы хотите создать репозиторий именно так, чтобы в будущем вы могли легко заменить EF на NHbibernate или что-то еще? Звучит здорово, но действительно ли это экономически выгодно?

Linq убивает модульные тесты?

Мне бы хотелось увидеть примеры того, как это можно убить.

Инъекция зависимостей, IoC

Ничего себе, это отличные слова, они отлично смотрятся в теории, но иногда вам приходится выбирать компромисс между отличным дизайном и отличным решением. Мы все это использовали, и мы закончили тем, что бросали все на мусор и выбирали другой подход. Размер против скорости (размер кода и скорость разработки) имеет огромное значение в реальной жизни. Пользователям нужна гибкость, им все равно, будет ли ваш код превосходным в дизайне с точки зрения DI или IoC.

Если вы не создаете Visual Studio

Все эти великолепные дизайны необходимы, если вы строите сложную программу, такую ​​как Visual Studio или Eclipse, которая будет разработана многими людьми, и она должна быть очень настраиваемой. Все большие модели развития вступили в картину после многих лет развития, которые прошли эти IDE, и они эволюционировали на месте, где все эти большие шаблоны дизайна имеют большое значение. Но если вы делаете простую веб-заработную плату или простое деловое приложение, вам лучше развиваться в вашем развитии со временем, а не тратить время на его создание для миллионов пользователей, где он будет развернут только для 100 пользователей.

Репозиторий как фильтрованный вид - ISecureRepository

С другой стороны, репозиторий должен быть фильтрованным представлением EF, который защищает доступ к данным, применяя необходимый наполнитель на основе текущего пользователя/роли.

Но это усложняет репозиторий еще больше, поскольку он заканчивается огромной базой кода для поддержки. Люди создают различные репозитории для разных типов пользователей или комбинации типов сущностей. Не только это, мы также получаем множество DTO.

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

Отказ от ответственности: я являюсь автором Entity REST SDK.

http://entityrestsdk.codeplex.com

Помня об этом, мы разработали SDK, который создает репозиторий фильтрованного представления на основе SecurityContext, который содержит фильтры для операций CRUD. И только два типа правил упрощают любые сложные операции. Первый - это доступ к объекту, а другой - правило чтения/записи для свойства.

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

public class DefaultSecurityContext : BaseSecurityContext {

  public static DefaultSecurityContext Instance = new DefaultSecurityContext();

  // UserID for currently logged in User
  public static long UserID{
       get{
             return long.Parse( HttpContext.Current.User.Identity.Name );
       }
  }

  public DefaultSecurityContext(){
  }

  protected override void OnCreate(){

        // User can access his own Account only
        var acc = CreateRules<Account>();

        acc.SetRead( y => x=> x.AccountID == UserID ) ;
        acc.SetWrite( y => x=> x.AccountID == UserID );

        // User can only modify AccountName and EmailAddress fields
        acc.SetProperties( SecurityRules.ReadWrite, 
              x => x.AccountName,
              x => x.EmailAddress);

        // User can read AccountType field
        acc.SetProperties<Account>( SecurityRules.Read, 
              x => x.AccountType);

        // User can access his own Orders only
        var order = CreateRules<Order>();
        order.SetRead( y => x => x.CustomerID == UserID );

        // User can modify Order only if OrderStatus is not complete
        order.SetWrite( y => x => x.CustomerID == UserID 
            && x.OrderStatus != "Complete" );

        // User can only modify OrderNotes and OrderStatus
        order.SetProperties( SecurityRules.ReadWrite, 
              x => x.OrderNotes,
              x => x.OrderStatus );

        // User can not delete orders
        order.SetDelete(order.NotSupportedRule);
  }
}

Эти правила LINQ оцениваются в отношении метода Database в SaveChanges для каждой операции, и эти правила действуют как брандмауэр перед базой данных.

Ответ 5

Существует много споров о том, какой метод является правильным, поэтому я рассматриваю его как приемлемый, поэтому я использую когда-либо тот, который мне больше всего нравится (который не является репозиторием, UoW).

В EF UoW реализуется через DbContext, а DbSets - это репозитории.

Что касается работы с уровнем данных, я просто непосредственно работаю над объектом DbContext, для сложных запросов я буду применять методы расширения для запроса, который можно использовать повторно.

Я считаю, что Айенде также имеет некоторые сообщения о том, как абстрагироваться от CUD-операций.

Я всегда создаю интерфейс и наследую свой контекст, поэтому я могу использовать контейнер IoC для DI.

Ответ 6

Linq - это теперь "репозиторий".

ISession + Linq уже является репозиторием, и вам не нужны ни методы GetXByY, ни QueryData(Query q). Будучи немного параноидальным для использования DAL, я по-прежнему предпочитаю интерфейс репозитория. (С точки зрения ремонтопригодности мы также должны иметь некоторый фасад над конкретными интерфейсами доступа к данным).

Здесь используется репозиторий - он отключает нас от прямого использования nhibernate, но предоставляет интерфейс linq (как доступ ISession в исключительных случаях, которые в конечном итоге подлежат рефактору).

class Repo
{
    ISession _session; //via ioc
    IQueryable<T> Query()
    {
        return _session.Query<T>();
    }
}

Ответ 7

Репозиторий (или, тем не менее, один из них называет его) в это время для меня, в основном касается абстрагирования слоя сохранения.

Я использую его в сочетании с объектами запроса, поэтому у меня нет связи с какой-либо конкретной технологией в моих приложениях. Кроме того, это значительно облегчает тестирование.

Итак, я склонен иметь

public interface IRepository : IDisposable
{
    void Save<TEntity>(TEntity entity);
    void SaveList<TEntity>(IEnumerable<TEntity> entities);

    void Delete<TEntity>(TEntity entity);
    void DeleteList<TEntity>(IEnumerable<TEntity> entities);

    IList<TEntity> GetAll<TEntity>() where TEntity : class;
    int GetCount<TEntity>() where TEntity : class;

    void StartConversation();
    void EndConversation();

    //if query objects can be self sustaining (i.e. not need additional configuration - think session), there is no need to include this method in the repository.
    TResult ExecuteQuery<TResult>(IQueryObject<TResult> query);
}

Возможно добавить методы async с обратными вызовами в качестве делегатов. Репо легко реализовать в общем, поэтому я не могу коснуться строки реализации из приложения в приложение. Ну, это правда, по крайней мере, при использовании NH, я сделал это также с EF, но сделал меня ненавидеть EF. 4. Разговор - это начало транзакции. Очень классно, если несколько классов совместно используют экземпляр репозитория. Кроме того, для NH одно репо в моей реализации равно одному сеансу, который открывается по первому запросу.

Затем Объекты запроса

public interface IQueryObject<TResult>
{
    /// <summary>Provides configuration options.</summary>
    /// <remarks>
    /// If the query object is used through a repository this method might or might not be called depending on the particular implementation of a repository.
    /// If not used through a repository, it can be useful as a configuration option.
    /// </remarks>
    void Configure(object parameter);

    /// <summary>Implementation of the query.</summary>
    TResult GetResult();
}

Для конфигурации, которую я использую в NH только для передачи в ISession. В EF нет смысла более или менее.

Пример запроса:.. (NH)

public class GetAll<TEntity> : AbstractQueryObject<IList<TEntity>>
    where TEntity : class
{
    public override IList<TEntity> GetResult()
    {
        return this.Session.CreateCriteria<TEntity>().List<TEntity>();
    }
}

Чтобы выполнить запрос EF, вы должны иметь контекст в базе абстрактных, а не в сеансе. Но, конечно, ifc будет одинаковым.

Таким образом, сами запросы инкапсулируются и легко проверяются. Лучше всего, мой код опирается только на интерфейсы. Все очень чисто. Доменные (бизнес-объекты) - это именно то, что, например, не происходит смешивания обязанностей, например, при использовании активного шаблона записи, который вряд ли тестируется, и смешивает код доступа к данным (запрос) в объекте домена и при этом смешивает проблемы (объект, который извлекает себя?). Все могут свободно создавать POCO для передачи данных.

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

И большое спасибо Айенде за его большие посты и постоянную преданность делу. Его идеи здесь (объект запроса), а не мои.

Ответ 8

То, что наиболее применимо к EF, не является шаблоном репозитория. Это шаблон Facade (абстрагирование вызовов EF-методов на более простые и простые в использовании версии).

EF - это тот, который применяет шаблон репозитория (и шаблон Единицы работы). То есть EF является абстрагирующим уровень доступа к данным, так что пользователь понятия не имеет, что он имеет дело с SQLServer.

И при этом большинство "репозиториев" над EF не являются даже хорошими Фасадами, поскольку они просто сопоставляют, довольно прямо, с одиночными методами в EF, даже с точки зрения наличия одинаковых сигнатур.

Таким образом, две причины для применения этого так называемого шаблона "Репозиторий" над EF - это упростить тестирование и установить подмножество "консервированных" вызовов. Неплохо сами по себе, но явно не репозиторий.

Ответ 9

Для меня это простое решение с относительно небольшим количеством факторов. Факторы:

  • Репозитории предназначены для классов домена.
  • В некоторых моих приложениях классы домена такие же, как мои классы персистентности (DAL), в других - нет.
  • Если они совпадают, EF уже предоставляет мне репозитории.
  • EF обеспечивает ленивую загрузку и IQueryable. Мне это нравится.
  • Тестирование/ "фасад" /повторное внедрение репозитория над EF обычно означает потерю лени и IQueryable

Итак, если мое приложение не может оправдать # 2, отдельные модели домена и данных, тогда я обычно не буду беспокоиться о # 5.