Рекомендуется ссылаться на другой совокупный корень по идентификатору, а не по ссылке (см. «Реализация доменного дизайна», стр. 359 и далее).

// direct reference
class AggregateRootA(val b: AggregateRootB)

// reference by ID (preferred)
class AggregateRootA(val b: AggregateRootBId)

class AggregateRootB(val id: AggregateRootBId)
class AggregateRootBId(val id: Long)

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

Интересно, является ли хорошей или плохой идеей использовать отношение внешнего ключа в базе данных при использовании ссылки по идентификатору в коде. Это ограничение будет обеспечивать согласованность на уровне базы данных, поскольку не может быть записи в базе данных AggregateRootA без ссылки на AggregateRootB. По сути, это то, что я хочу, так как в противном случае объект был бы недействительным.

Есть ли здесь какой-то недостаток в использовании внешнего ключа, кроме немного более громоздкого тестирования?

1
deamon 28 Май 2019 в 18:08

2 ответа

Лучший ответ

Есть ли здесь какой-то недостаток в использовании внешнего ключа, кроме немного более громоздкого тестирования?

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

Таким образом, если у вас есть реальная деловая озабоченность, что бухгалтерия о B должна происходить до того, как бухгалтерия связывает A с B, тогда применение этого ограничения в базе данных - это хорошо.

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

Короче говоря, тщательно измерьте затраты, связанные с наличием ограничения, с преимуществами его наличия.

2
VoiceOfUnreason 28 Май 2019 в 15:36

Это слишком долго, чтобы добавить его в качестве комментария, но я просто добавляю к тому, что @VoiceOfUnreason ответил, поэтому, пожалуйста, примите этот ответ, а не этот :)

Просто чтобы быть педантичным по этому поводу: вы имеете в виду DRI (декларативную ссылочную целостность), поскольку даже отношение внешнего ключа может быть отключено.

В DRI нет ничего плохого по своей сути, так как он имеет довольно обоснованное назначение. Разумеется, это будет иметь смысл в том же ограниченном контексте, что и данные в одной базе данных. Для разных BC вы можете либо вообще отказаться от применения отношения и работать только с денормализованными данными, либо применить отношение, сохраняя объекты-значения в хранилище данных вашего BC. Агрегаты из "чужого" БК будут ВО в вашем БК. В этом случае все, что упомянуто @VoiceOfUnreason вступает в игру. В некоторых случаях может иметь смысл обеспечить, чтобы определенные изменения состояния происходили в разумном порядке. Например, вы, возможно, захотите зарегистрировать клиента, прежде чем активировать телефонную линию.

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

1
Eben Roux 28 Май 2019 в 17:16