Являются ли шаблоны единиц работы и репозитория очень полезными для больших проектов? - PullRequest
25 голосов
/ 29 октября 2011

Я начинаю новый веб-проект с использованием ASP.NET Webforms + EF4. Я пытаюсь применить шаблон репозитория с шаблоном единицы работы, следуя этому руководству: http://www.dotnetage.com/publishing/home/2011/07/05/6883/the-repository-pattern-with-ef-code-first-dependeny-injection-in-asp-net-mvc3.html

Мне кажется, я понял идею, но мой вопрос в том, что, когда я создаю новый объект в модели, должен ли я также определять этот объект в IDALContext из Unit Work? Разве это не ручная работа для быстрого развития? Также, если вы работаете с несколькими разработчиками и не хотите, чтобы другие разработчики видели ваш DAL, как вы можете управлять этим? Потому что в этом шаблоне, как я понимаю, когда вы создаете новый объект в модели, вы также должны определить его в IDALContext для этого урока. Извините, я так смущен этим.

Ответы [ 4 ]

96 голосов
/ 29 октября 2011

Теперь первый вопрос должен быть: зачем вообще нужен репозиторий или единица работы? Не могу ли я просто использовать контекст EF из контроллера, имея полную мощность напрямуюнаписать запрос, который мне нужен, и вернуть данные?
Ответ: Можно, но реальная цель - тестируемость и, следовательно, более качественный, более обслуживаемый код.Если вы разделили доступ к данным и сконцентрировали его в одном месте, вы можете макетировать их во время тестирования.Это позволяет вам unit тестировать логику, определенную в вашем контроллере, без эффективной записи в хранилище данных.

Перед началом работы с Unit of Work, просто посмотрите на Шаблон репозитория .Это в основном абстрагирует доступ к данным для данного объекта.Таким образом, вы определяете методы, такие как Filter (), All (), Update (..), Insert (..), Delete (...) и, наконец, Save ().На самом деле большинство из них можно довольно легко абстрагировать к классу BaseRepository<TEntity>, так что в конце вам просто нужно будет создать новый репозиторий в редких случаях со специальным поведением.В противном случае это будет что-то вроде BaseRepository<Person> personRepo = new BaseRepository<Person>() или BaseRepository<Address> addressRepo = new BaseRepository<Address>() и т. Д.

Зачем нужна единица работы?
Единица работы представляет все операции, выполненные в течение определенного цикла, в веб-среде обычно по запросу Http.Это означает, что при поступлении нового запроса вы создаете новую единицу работы, добавляете новую вещь, обновляете или удаляете ее, а затем «фиксируете» изменения, вызывая .save() или .commit() .. как угодно.На самом деле, если вы внимательно посмотрите на Entity Framework DbContext (или ObjectContext), они уже представляют какую-то единицу работы.
Однако, если вы хотите дополнительно абстрагировать ее, потому что вам не обязательно иметьКонтекст EF в ваших классах контроллеров (помните: testable), затем вы создаете UoW для группировки ваших репозиториев, а также для обеспечения того, чтобы все они совместно использовали один и тот же экземпляр контекста EF.Вы можете достичь последнего также с помощью контейнера DI (контейнера Dependency Injection).

На ваши вопросы: он полезен в больших проектах? :
Определенно, особенно в большие проекты.Все дело в разделении обязанностей (доступ к данным, бизнес-логика, логика предметной области) и, таким образом, к проверке.

18 голосов
/ 29 октября 2011

Мартин Фаулер описывает роль хранилища следующим образом: «Репозиторий является посредником между доменом и слоями отображения данных, действуя как коллекция объектов домена в памяти».В сущности Entity Framework 4.1 является хранилищем в этом смысле.Кроме того, в EF встроено единство работы. Поэтому я советую игнорировать статью в блоге, которую вы упомянули в своем вопросе.

Код, подобный этому, не только бесполезен или бесполезен, но и опасен, поскольку к нему не добавляется никакой выгодываш код, но зависимость!

public interface IUnitOfWork:IDisposable
{
    int SaveChanges();
}

public interface IDALContext : IUnitOfWork
{
    ICategoryRepository Categories { get; }
    IProductRepository Products { get; }
}

Чтобы ответить на ваш вопрос, имея некоторую абстракцию, которая является посредником между доменом и слоями отображения данных, работа в качестве коллекции объектов домена в памяти является обязательной для «больших» проектов.А наличие механизма UnitOfWork под капотом может помочь отделить вашу бизнес-логику от доступа к некоторой абстракции доступа к данным.

TL; TR;Репозиторий и UnitOfWork могут помочь вам, но не применяйте его, как в данном сообщении в блоге.

4 голосов
/ 20 октября 2015

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

Итак, чтопроблемы, которые решает шаблон хранилища?

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

2- Лучшее разделение интересов: Представьте себе сложный запрос для получения наиболее продаваемых курсов в данной категории, который включает в себя активную загрузку, объединение, группировку, фильтрацию и т. Д.

Когда вы реализуете такие большие сложные запросы в своих сервисах / контроллерах, вы получите толстые сервисы / контроллеры.Эти классы становятся сложными для модульного тестирования, так как они потребуют много шумных заглушек.Ваши юнит-тесты становятся длинными, жирными и не поддерживаемыми.

Если вы столкнулись с этой проблемой, возможно, вы могли бы подумать об использовании шаблона хранилища.В этом примере мы можем инкапсулировать сложный запрос, чтобы получить наиболее продаваемые курсы в репозитории:

courseRepository.GetTopSellingCourses(int categoryId, int count);

Таким образом, ваши службы / контроллер больше не будут иметь дело с быстрой загрузкой, объединением, группировкой и т. Д. Вместо этого, они делегируют в хранилище.Помните, что энергичная загрузка, объединение и группировка и т. Д. Являются запросом логики и относятся к вашему уровню доступа к данным, а не к вашим услугам или уровню представления.

3- Отделение архитектуры вашего приложения от сред постоянства: когда вы используете классы Entity Framework (например, DbContext, DbSet и т. Д.) Непосредственно в своем приложении, ваше приложение тесно связано с Entity Framework.Если вы планируете переключиться на другой O / RM в будущем или даже на более новую версию Entity Framework с другой моделью, вам, возможно, придется изменить многие части вашего приложения, и это может привести к новым ошибкам в вашем приложении.Вы можете использовать шаблон репозитория, чтобы отделить архитектуру вашего приложения от сред постоянства, таких как Entity Framework.Таким образом, у вас будет свобода перехода на другой O / RM с минимальным влиянием на ваше приложение.

Просмотрите это видео для получения более подробной информации:

https://youtu.be/rtXpYpZdOzM

1 голос
/ 12 января 2018

Вы должны рассмотреть «объекты команды / запроса» в качестве альтернативы, вы можете найти кучу интересных статей в этой области, но вот хорошая:

https://rob.conery.io/2014/03/03/repositories-and-unitofwork-are-not-a-good-idea/

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

Однако, если вы думаете, что объект Query для запроса является излишним, вы могли быну будь на 100% прав.Часто вы можете начать с объекта «FooQueries», который по сути является репозиторием, но только для запросов.«Foo» может быть вашим «доменным агрегатом» в смысле DDD.

Вы можете найти отдельные объекты запросов полезными позже.

Как и в большинстве случаев, которые вы должны учитывать в системе по системе.

...