DDD - обрабатывает ли хранилище агрегатного корня сохранение агрегатов?

27

Я использую DDD-подобный подход для нового модуля существующего приложения; это не 100% DDD из-за архитектуры, но я пытаюсь использовать некоторые концепции DDD. У меня есть ограниченный контекст (я думаю, что это правильный термин - я все еще изучаю DDD), состоящий из двух сущностей: Conversationи Message. Беседа является корнем, поскольку Сообщение не существует без диалога, и все сообщения в системе являются частью диалога.

У меня есть ConversationRepositoryкласс (хотя он действительно больше похож на шлюз, я использую термин «хранилище»), который находит беседы в базе данных; когда он находит беседу, он также создает (через фабрики) список сообщений для этой беседы (отображается как свойство). Похоже, что это правильный способ обработки вещей, поскольку нет необходимости в полномасштабном MessageRepositoryклассе, поскольку он существует только при извлечении беседы.

Однако когда речь идет о сохранении сообщения, несет ли это ответственность ConversationRepository, так как это совокупный корень сообщения? Я имею в виду, должен ли я иметь метод в ConversationRepository, который называется, скажем, AddMessageкоторый принимает сообщение в качестве параметра и сохраняет его в базе данных? Или у меня должен быть отдельный репозиторий для поиска / сохранения сообщений? Логичной вещью является один репозиторий на сущность, но я также слышал «Один репозиторий на контекст».

Уэйн Молина
источник

Ответы:

25

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

Группа из двух сущностей, о которых вы упоминаете, не является ограниченным контекстом - скорее всего, это совокупность. Каждый Агрегат имеет Агрегированный Корень, Сущность, которая служит единой точкой входа в Агрегат для всех других объектов. Таким образом, нет прямой связи между сущностью и другой сущностью в другой совокупности, которая не является корнем совокупности.

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

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

ConversationRepository будет играть роль в сохранении сообщений, но не такую ​​прямую, как вы упоминаете. Таким образом, AddMessage () в ConversationRepository (этот метод скорее принадлежит к самой беседе), но вместо этого каждый раз, когда репозиторий будет сохранять беседу, будет хорошей идеей сохранять свои сообщения одновременно, либо прозрачно, если вы используете платформу ORM такие как (N) Hibernate, использование специального SQL, если вы выберете, и т. д.

guillaume31
источник
1
Если у объединенного корня, такого как Conversation, много разных типов объектов, таких как Message, Thingies и Wingies, то при сохранении диалога, например ConversationRepo.save (разговор), откуда вы знаете, какие сущности в нем нужны быть спасенным? В приведенном выше примере постеров необходимо сохранить только сущности сообщения. Обходите ли вы все возможные коллекции в объединенном корне, чтобы найти сущности без идентификаторов?
Крис-Ричардс
3

Вы можете создать ConversationService и внедрить IConversationRepository и IMessageRepository в его конструктор. Используйте репозитории для простых операций CRUD и сервисы для всего остального (кэширование, сохранение логики и т. Д.)

šljaker
источник
1
не спасает логика CRUD?
Тимоти Грут