DDD / Aggregate Root / Элемент-член, указывающий на корневой объект

Можно ли, чтобы сущность-член совокупного корня указывала на корневую сущность (а не наоборот)?

Предположим, у меня есть Population AR (где Population — это корневая сущность, а PopulationMembership — одна из сущностей-членов).

Я оцениваю направление связи между Population и PopulationMembership. На другом конце есть еще одна сущность, Person (собственный AR, а PopulationMembership имеет ссылку на Person).

В мире ER (базы данных) мы обычно делаем ассоциацию, указывающую от PopulationMembership к Population (population_membership — это связующая таблица в отношениях «многие ко многим» между Population и Person).

Но я думаю, что в мире DDD я должен отказаться от этой привычки и вместо этого сделать ассоциацию, указывающую от Population (в концептуальной модели) к PopulationMembership.

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

Есть предположения?


person Cokorda Raka    schedule 06.03.2017    source источник
comment
Возможно, это как-то связано с моим вопросом: stackoverflow.com/questions/9804815/ С этой особенностью: при наличии связи между сущностью A и сущностью B вы часто обнаружите, что используете только AB и никогда BA Это может быть связано с тем, что A является совокупным корнем и всегда является вашей отправной точкой, потому что у вас уже есть ссылка на его A везде, где вы манипулируете B, и т. д. Это предполагает, что (по крайней мере), когда сущность напрямую связана с корневой сущностью, направление всегда исходит от корневой сущности. Правильно?   -  person Cokorda Raka    schedule 06.03.2017
comment
Возможный дубликат направления обхода ассоциаций   -  person guillaume31    schedule 07.03.2017


Ответы (1)


Хорошо, давайте разделим этот вопрос на две части:

  1. Можно ли объекту-члену хранить ссылку на его совокупный корень?
  2. Общие правила моделирования агрегатов

Начнем с 1:

Нет, как правило, дочерние объекты не должны содержать ссылки на корни агрегатов. Корень агрегата является точкой входа для всего агрегата и должен поддерживать свои границы согласованности. Это означает, что каждое изменение агрегата должно быть перенаправлено через корневой объект (в oop путем вызова методов корневого объекта). Совокупный корень может возвращать ссылки на дочерние объекты, но они должны быть временными. Кроме того, клиент не должен вносить изменения в дочерние объекты за пределами корня агрегата, иначе может быть нарушена согласованность. Имея это в виду, я действительно не вижу причин для дочерних сущностей хранить ссылки на свой корень (с точки зрения клиента — у вас уже есть доступ к корню, не так ли?). Единственное исключение, которое я вижу прямо сейчас, это когда вам нужно преобразовать модель в некоторые конкретные потребности (например, уровень представления требует идентификатора корневого объекта для получения значимого вывода JSON). Однако даже в этом случае вы, вероятно, создадите отдельную модель чтения или предоставите специализированные ассемблеры для создания необходимых DTO.

Хорошо, теперь ко второму пункту:

Кажется, вы пытаетесь смоделировать свои доменные сущности так же, как вы строите модель своей базы данных. В DDD мы должны сначала сосредоточиться на бизнес-требованиях и поведении нашей модели. Отношения данных не так важны при построении значимой модели предметной области (мы уточним это чуть позже). Итак, в первую очередь вам следует сосредоточиться на сборе сценариев бизнес-кейсов от экспертов в вашей области. Агрегаты должны строиться на реальных бизнес-инвариантах. Вы должны создать общую модель вместе со своей командой (включая представителей бизнеса). Очень вероятно, что ваш дизайн будет выглядеть совершенно по-другому после нескольких сеансов обработки знаний. Может быть, Person на самом деле не совокупный корень, а просто объект-значение? Может быть, вам даже не нужна сущность PopulationMembership? Наиболее распространенный дизайн для агрегатов — это всего лишь один (корневой) объект с несколькими объектами-значениями. Кроме того - я часто создаю полностью отдельную модель базы данных, практически не привязываясь (кроме id) к модели предметной области. Я использую слой перевода (компоненты сопоставления) для преобразования между domain‹->dbmodel. В моем недавнем проекте моя модель базы данных сильно отличалась от уровня предметной области (она была адаптирована специально к потребностям уровня постоянства — так, например, использовалось много плоских свойств — не полные объекты, а простые примитивные значения). В случае реляционной базы данных вы можете даже явно указать двунаправленную связь (на самом деле вам даже не нужно использовать какую-либо форму). Есть много преимуществ в отделении вашей модели БД от модели предметной области. Дизайн определенно стал более гибким. Однако стоимость сопоставления (работа разработчика) между db ‹-> доменным уровнем может быть слишком большой для простых проектов. В таком случае я обычно начинаю с общей модели, а затем выполняю рефакторинг на отдельные слои.

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

Пожалуйста, обратитесь к замечательной серии статей Вона Вернона:

http://dddcommunity.org/library/vernon_2011/

Я думаю, что эти статьи могут помочь вам понять концепции агрегатного моделирования.

person Mike Wojtyna    schedule 07.03.2017
comment
Я хотел бы добавить, что для того, чтобы отделить модель предметной области от модели базы данных (как вы ее назвали), вы можете использовать CQRS, где есть две отдельные модели: модель записи (также известная как агрегаты) и модель чтения (какой пользовательский интерфейс/ Презентация видит). Если вы выберете CQRS, то это разделение будет очень естественным и четким. - person Constantin Galbenu; 07.03.2017
comment
@ConstantinGALBENU спасибо за ваш комментарий. Да, создавать отдельные модели для чтения и записи — хорошая идея. Эти модели могут даже использовать разные базы данных, адаптированные к конкретным потребностям разных слоев. Однако в своем ответе я использовал термин «модель базы данных» для описания классов только для данных (без логики), отображаемых непосредственно из базы данных. В зависимости от технологии, которую мы используем, наши классы предметной области могут быть почти идентичны нашим классам, отображаемым в базе данных, или быть совершенно разными (например, классы предметной области используют сложные объекты, а не плоские примитивы в классах, отображаемых в базу данных). - person Mike Wojtyna; 08.03.2017