Зачем мне использовать UnitOfWork с шаблоном репозитория? - PullRequest
4 голосов
/ 02 января 2012

Я много видел о UnitOfWork и Repo Pattern в Интернете, но до сих пор не имею четкого понимания, почему и когда использовать - это меня несколько смущает.

Учитывая, что я могу сделать свои репозитории тестируемыми, используя DI, используя IoC, как предлагается в этом посте Каковы наилучшие методы управления DataContext .Я рассматриваю передачу контекста как зависимость от моего конструктора репозитория, а затем избавляюсь от него следующим образом?- это поведение противоречит тому, что @Ladislav Mrnka рекомендует для веб-приложений:

Для веб-приложений используйте один контекст для запроса.Для веб-сервисов используйте один контекст на вызов.В приложении WinForms или WPF используйте один контекст для формы или для докладчика.Могут быть некоторые особые требования, которые не позволят использовать этот подход, но в большинстве случаев этого достаточно.

См. Полный ответ здесь

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

Мои репо зарегистрированы в IoC как временные, поэтому я должен получитьновый с каждым запросом.Если это правильно, то я должен получать новый контекст (с кодом выше) с каждым запросом, а затем избавляться от него - который говорит ... Зачем мне использовать шаблон UnitOfWork с шаблоном репозитория, если ясоблюдаешь соглашение выше?

Ответы [ 3 ]

6 голосов
/ 02 января 2012

Насколько я понимаю, шаблон «Единица работы» не обязательно охватывает несколько контекстов. Он просто инкапсулирует одну операцию или - хорошо - единицу работы, похожую на транзакцию.

Создание вашего контекста в основном запускает Unit of Work; вызов DbContext.SaveChanges() завершает его.

Я бы даже сказал, что в своей текущей реализации Entity Framework DbContext / ObjectContext напоминает и шаблон хранилища, и шаблон единицы работы.

3 голосов
/ 02 января 2012

Я бы использовал упрощенное UoW, если бы я хотел отодвинуть контекстные SaveChanges от репозиториев, когда они совместно используют один и тот же экземпляр контекста в одном веб-запросе.

Я полагаю, что в ваших репозиториях есть метод Save (), похожий на _customObjectContext.SaveChanges(). Теперь давайте предположим, что у вас есть два метода, содержащие бизнес-логику и использующие репозитории для сохранения изменений в БД. Для простоты мы назовем их MethodA и MethodB, оба из которых содержат достаточное количество логики для выполнения некоторых действий. MethodA используется отдельно в системе, но также почему-то вызывается MethodB. Происходит следующее: MethodA сохраняет изменения в некотором репозитории, и поскольку мы все еще выполняем тот же запрос, изменения, сделанные в MethodB, до того как он вызвал MethodA, также будут сохранены независимо от того, хотим мы этого или нет. Поэтому в этом случае мы непреднамеренно нарушаем транзакцию внутри MethodB и усложняем понимание кода.

Надеюсь, я достаточно ясно это описал, это было нелегко. Во всяком случае, кроме этого, я не могу понять, почему UoW будет полезным в вашем сценарии. Как правильно сказал Деннис Трауб, ObjectContext и DbContext на самом деле являются реализацией UoW, поэтому вы, вероятно, будете изобретать велосипед, внедряя его самостоятельно.

1 голос
/ 02 января 2012

ObjectContext/DbContext является реализацией шаблона UnitOfWork. Он инкапсулирует несколько операций и обеспечивает их отправку в одну транзакцию в базу данных.

Единственное, что вы делаете, это заключаете его в свой собственный класс, чтобы убедиться, что вы не зависите от конкретной реализации в остальной части вашего кода.

В вашем случае проблема заключается в том, что ваш Context не должен утилизироваться вашим Repository. Repository - это не тот, который создает экземпляр Context, поэтому он также не должен им распоряжаться. UnitOfWork, который включает в себя несколько репозиториев, отвечает за создание и удаление Context, и вы вызовете метод Save на вашем UnitOfWork.

Код может выглядеть так:

using (IUnitOfWork unitOfWork = new UnitOfWork())
{
   PersonRepository personRepository = new PersonRepository(unitOfWork);
   var person = personRepository.FindById(personId);

   ProductRepository productRepository = new ProductRepository(unitOfWork);
   var product= productRepository.FindById(productId);

   p.CreateOrder(orderId, product);
   personRepository.Save();
}
...