Агрегаты DDD: идентификатор объекта хранения для некорневого объекта в другом агрегате

Я пытаюсь понять лучшие практики для отношений между сущностями и агрегатами.

Представьте себе проект, в котором у вас есть Совокупный продукт, состоящий из двух сущностей:

Совокупный корень: продукт

Дочерняя сущность: Sku

Где у продукта может быть много Skus. Номера деталей и названия Skus и Product неизменны, поскольку изменение названия одного должно транзакционно обеспечить обновление другого. Точно так же агрегат продукта должен гарантировать, что никогда не будет дублироваться Skus.

У нас есть еще один Агрегат: StorageLocation. где хранится 1 или более Skus. Однако важно, чтобы StorageLocation знал конкретный Sku, который он хранит. т.е. В StorageLocation в Канаде должны храниться Sku, локальные для этой страны, а не Sku, предназначенные для рынка США.

Для меня это означает, что StorageLocation должен хранить ссылку на Sku (поскольку ссылка на агрегированный корень продукта сама по себе не предоставляет достаточно информации для определения сохраняемой Sku).

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

  • Допустимо ли хранение только идентификатора продукта и артикула в агрегате StorageLocation?
  • Я знаю, что временная ссылка считается допустимой, но в этом случае (по крайней мере, насколько я могу судить) эту информацию необходимо сохранить. Как уже упоминалось, хранения ссылки на Продукт (или ProductId) недостаточно.
  • Продукт и артикул имеют естественные идентификаторы (номер детали, номер артикула). Обеспечивает ли это большую гибкость для хранения этих значений в агрегате StorageLocation, поскольку они имеют значение, выходящее за рамки технических аспектов.
  • Неправильно ли я подхожу к этому, и мне нужно смотреть на вещи по-другому? Мне часто трудно отказаться от мышления PK / FK.

Спасибо

Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
6
0
1 073
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Рекомендация не хранить ссылку на дочернюю сущность основывается на хороших принципах, но я считаю, что часто вызывает путаницу. На самом деле цель состоит в том, чтобы дочерняя сущность не обязательно имела «глобально уникальный» идентификатор и чтобы ни один репозиторий не предоставлял прямой доступ к дочерней сущности с использованием такого глобально уникального идентификатора.

Однако, если ваш StorageLocation содержит глобальный уникальный идентификатор для Product, а также, возможно, локальный уникальный идентификатор для SKU, тогда нет ничего плохого в таких шаблонах, как:

var storageLocation = _storageLocationRepository.Get(id);
var product = _productRepository.Get(storageLocation.ProductId);
product.DoSomethingToSku(storageLocation.SkuId);

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

Итак, подведем итог:

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

«Руководство не хранить ссылку на дочернюю сущность основано на хороших принципах, но я считаю, что часто вызывает путаницу». Да, согласен. В вашем резюме есть два хороших руководящих принципа. Спасибо.

Steven 15.03.2018 22:07

Is holding just an identifier to the Product and Sku in the StorageLocation aggregate acceptable?

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

I'm aware that a transient reference is deemed allowable, but in this instance (at least as far as I can tell) this information needs to be stored. As mentioned, storing a reference to the Product (or ProductId) is not enough.

Обезвоживание корня агрегата StorageLocation обратно в базу данных должно включать все, что необходимо сохранить. Уровень инфраструктуры определяет, как ваши объекты домена хранятся в физическом репозитории, и может представлять собой совершенно иной дизайн модели, чем ваша модель предметной области, в зависимости от проблем, связанных с технологией сохранения.

Product and Skus have natural identifiers (Part Number, Sku Number). Does this provide greater flexibility for storing these values in the StorageLocation aggregate as they have meaning beyond technical implications.

Нет ничего, с чем можно было бы сравнивать «большую гибкость», потому что вы будете использовать только естественные идентификаторы или временные ссылки для ссылки на сущности внутри агрегата Product из агрегата StorageLocation.

Am I approaching this the wrong way and need to look at things differently. I often find it difficult to break out of a PK / FK mindset.

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

Другие вопросы по теме