Можно ли обойти шаблон хранилища для сложных запросов? - PullRequest
18 голосов
/ 03 сентября 2011

Это мое понимание DDD на данный момент:

  • Строгий шаблон репозитория должен реализовывать только get (), delete () и create () и, возможно, варианты get (), где одинможет искать или извлекать всю коллекцию
  • Для каждого совокупного корня характерно наличие одного хранилища

(из исследований я знаю, что это не общепринятые нормы)

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

Как должен реализовываться этот запрос?

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

  2. Использовать только репозиторий для продукта и пользователя, захватывать все записи и делать все в памяти (это звучит неправильно)

  3. Есть запрос (LINQ или SQL) находиться внутри службы, вообще не используя репозиторий, связанный с агрегатами.

Существуют ли другие способы?

Ответы [ 3 ]

16 голосов
/ 03 сентября 2011

Строгий шаблон репозитория должен реализовывать только get (), delete () и create () и, возможно, варианты get (), где можно искать или извлекать всю коллекцию

Интерфейс репозитория является частью вашего домена и должен быть максимально основан на Ubiquitous Language .Все хранилища разные, как и все ваши агрегаты.Строгое, универсальные репозитории являются чрезмерной генерацией CRUD и могут снизить выразительность кода.Метод 'Create' также не принадлежит Repository, потому что начало жизненного цикла объекта обычно обрабатывается Factory или самим объектом.«Добавить» выглядит лучше, если вы хотите сохранить существующий объект, потому что репозиторий имеет семантику коллекции.

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

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

Products products = /* get Products repository implementation */;
IList<Product> res = products.BoughtByUser(User user);

Идея организации такого кода состоит в том, чтобы максимально соответствовать бизнес-требованиям и вездесущему языку.Имена интерфейсов репозитория также важны, я предпочитаю иметь Products или AllProducts вместо ProductsRepository .Фил Кальсадо имеет очень хорошую статью на эту тему, настоятельно рекомендуется.

How should this query be implemented?

Ничего особенного в этом запросе нет, он может быть реализован так же, как и все другие запросы в репозитории продуктов.Сам запрос скрыт от Домена, потому что репозиторий , реализация относится к уровню доступа к данным.Доступ к данным может реализовать любой запрос, поскольку он обладает глубокими знаниями обо всех агрегатах и ​​их взаимосвязях.На этом этапе это будет просто вопрос Hibernate или SQL.

14 голосов
/ 05 сентября 2011

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

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

Я написал пост в блоге, объясняющий эту концепцию некоторое время назад. Вы можете найти это здесь .

0 голосов
/ 03 сентября 2011

Просто поместите это в класс репозитория.Это Get, вероятно, в ProductRepository, поскольку это то, что он возвращает.GetProductsByUser (int UserID).Или, если у вас есть n-уровневая архитектура, то это может быть в методе обслуживания.

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

...