DDD: совокупный корневой вопрос

Скажем, у меня есть 2 объекта - Foo и Bar. Foo - это совокупный корень, содержащий Bar. Насколько я понимаю, это должно выглядеть так:

public class Foo{
    private readonly Bar Bar;
}

Я хочу предоставить пользователям возможность выбирать Bars for Foos из определенного списка (и изменять его).

Если предполагается, что репозитории предназначены только для агрегированных корней, это означает, что не будет репозитория для сущности Bar.

Это приводит к проблеме - Bar не может быть создан / обновлен независимо без ссылки на Foo.

Означает ли это, что у Bar должен быть репозиторий, несмотря на то, что он не имеет смысла без Foo?


person Arnis Lapsa    schedule 25.09.2009    source источник
comment
Нет такой вещи, как глупый вопрос, просто глупые ответы;) Кстати, этот вопрос мне очень помог   -  person Eldar    schedule 04.07.2014


Ответы (3)


Если вы хотите выбрать из списка Bars, где они не связаны с Foo, то это не совокупный корень. Например, вы не можете получить список OrderItems без их Order, поэтому это единый агрегированный корень (Order), но вы можете получить список продуктов для назначения OrderItems, поэтому Product не является частью агрегированного корня Order.

Обратите внимание, что хотя OrderItem является частью совокупного корня Order, вы все равно можете создавать и обновлять его независимо. Но вы не можете получить его без ссылки на Заказ. То же самое для вашего Bar, даже если он был частью Foo, вы могли бы получить каждый (Foo.Bars) и работать с ним, или сделать Foo.AddBar (new Bar ()). Но если вам нужно получить List без Foo, Bar не является частью агрегата Foo. Это отдельная сущность.

Ну, вот как я вижу здесь DDD, но я, конечно, не Эрик Эванс.

person queen3    schedule 25.09.2009
comment
Это имеет смысл. Если тебе есть что сказать - продолжай. :) - person Arnis Lapsa; 26.09.2009
comment
Я узнал, что в моей сфере слишком много общих корней. Существуют сущности, созданные как корни, несмотря на то, что они не должны обновляться независимо. Хуже того - некоторые корни можно заменить как объекты ценности. - person Arnis Lapsa; 26.09.2009
comment
Еще одно предложение, которое приходит мне в голову, заключается в том, что если ваш Bar является автономным (может быть представлен в виде отдельного списка) и зависимым (работает внутри Foo) одновременно - возможно, у вас здесь есть две сущности. Краткий пример: Group {Name, Price} - должна быть как внутри Order / Product, так и представлена ​​отдельно, но если вы разделите ее на Group {Name} и ProductGroup {Group, Price}, вы представите Group отдельно, сохраняя ProductGroup как часть агрегата. - person queen3; 27.09.2009
comment
@ queen3; Думаю, я понимаю вашу точку зрения, но не могли бы вы кое-что прояснить для меня. Используя другой пример ... Клиент - это совокупный корень, у которого есть страна. Чтобы установить страну, вам нужно выбрать ее из списка стран ... чтобы страна также стала совокупным корнем ... правильно? - person Craig; 20.01.2010
comment
Что ж, я бы сказал, что это делает Country отдельной сущностью. Это будет совокупный корень, если он содержит другие объекты (например, регион). Это если я правильно понимаю, что совокупный корень и сущность - разные звери ;-) Но это определенно не часть совокупного корня Клиента. Ну, в некоторых ситуациях он может быть частью клиента ... например, в игре с виртуальным миром, где пользователи создают свои собственные страны, страна может быть частью Мира игрока. Но я думаю, это не твой случай. - person queen3; 20.01.2010
comment
Тогда это имеет смысл ... страна в моем случае на самом деле просто объект, поскольку он не содержит регионов (хотя, возможно, и должен), но он похож на корневой объект, если я могу его назвать, что означает, что у него должно быть собственное репо . Клиент - это совокупный корень агрегата «Клиент / Страна» и, как таковой, имеет собственное репо для внесения в него изменений. Цените ваше мнение, спасибо! - person Craig; 20.01.2010
comment
Еще одно уточнение, насколько я понимаю, агрегированные корни не предназначены для того, чтобы содержать только свои внутренние сущности, они также могут иметь внешние сущности. Классическим примером, я полагаю, является заказ / позиция, и мы, конечно, можем ожидать, что у Order будет реселлер, а реселлер, что еще более очевидно, является отдельной внешней сущностью. Но иногда я задаюсь вопросом, имеют ли вообще значение эти термины ;-) - person queen3; 20.01.2010

Причины наличия совокупных корней:

  1. Они обеспечивают контролируемый и направленный доступ к составным объектам.
  2. Они могут применять правила, чтобы гарантировать, что весь агрегат действителен.

Мое мнение: Если вам нужно выбрать Bar объекты без Foo, используйте BarRepository.

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

Однако, если вам нужно получить доступ к группе Bar объектов (например, для пакетного задания или отчета), и вы знаете, что Foos не сломается, продолжайте и обращайтесь к ним через BarRepository.

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

person Vijay Patel    schedule 26.09.2009

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

person Fossmo    schedule 25.09.2009
comment
И почему объект не может быть получен через сервис и подключен к Foo? - person Arnis Lapsa; 26.09.2009
comment
Как объекты-значения должны создаваться / обновляться без контекста сущности? Разве это не маскировка службы под репозиторий, которого не должно быть у объекта значения? - person Arnis Lapsa; 26.09.2009
comment
Позвольте мне объяснить, как я это сделал; Мне нужен способ получить данные с постоянного уровня. Я мог бы использовать DTO для извлечения данных, но я предпочитаю использовать объект значения, потому что тогда я могу использовать объект в домене без сопоставления из DTO с объектом значения. Объект, который я использую, - это класс из совокупного корня, в вашем случае Bar. Если бы я сделал это для объекта, я бы использовал DTO (полученный через службу) для заполнения списка (поле со списком и т. Д.), И когда я выбрал правильную панель, я бы попросил репозиторий получить мне полный объект от совокупного корня. Надеюсь, это имеет смысл. - person Fossmo; 26.09.2009
comment
Интересно, может ли это решение вообще применяться к моему вопросу о проверке и выборе значений по умолчанию на основе данных, которые в противном случае являются внешними по отношению к агрегату. stackoverflow.com/questions/5454521/ - person jpierson; 29.03.2011