Должна ли реализация репозиториев быть изолированной, как их базовые агрегаты?
Преимущество наличия репозиториев при использовании DDD заключается в том, что они позволяют проектировать модель предметной области, не беспокоясь о том, как объекты будут сохраняться. Это также позволяет конечному продукту быть более гибким, поскольку различные реализации репозиториев можно легко вставлять и выгружать. Таким образом, реализация репозиториев может основываться на базах данных SQL, веб-службах REST, файлах XML или любом другом способе хранения и извлечения данных. С точки зрения модели ожидается, что есть только эти магические коллекции, которые можно использовать для хранения и извлечения совокупных корневых объектов.
Теперь, если у меня есть две нормальные коллекции в памяти, скажем IList<Order>
и IList<Customer>
Я бы никогда не ожидал, что изменение одной коллекции повлияет на другую. Так должна ли та же логика применяться к репозиториям? Должна ли фактическая реализация репозиториев быть полностью изолирована друг от друга, даже если они в действительности имеют доступ к одной и той же базе данных?
Например, отношение каскад при удалении может быть установлено в базе данных SQL между Customers
стол и Orders
таблица, так что соответствующие заказы удаляются при удалении клиента. Все же эта функциональность сломалась бы, если позже SQLCustomerRepository
заменяется RESTCustomerRepository
,
Итак, правильно ли я считаю, что модель всегда должна исходить из предположения, что репозитории полностью изолированы друг от друга, и, соответственно, фактическая реализация репозиториев также должна быть изолирована?
Так что если Orders
должны быть удалены, когда Customer
удаляется, должно ли это быть определено явно в модели предметной области, а не полагаться на базу данных? Скажи через CustomerService.DeleteCustomer()
метод, который обращается к текущему ICustomerRepository
а также IOrderRepository
,
Я думаю, что мне просто трудно вырваться из мира отношений в мир DDD. Я продолжаю хотеть думать о вещах с точки зрения таблиц и отношений PK/FK, где я должен просто игнорировать, что база данных вообще задействована.
4 ответа
Я считаю, что момент, который вы упускаете, заключается в том, что совокупные корни проводят границы контекста.
Проще говоря, материал под ним имеет смысл только вместе с самим агрегатным корнем.
На мой взгляд, Order - это не сводный корень, а сущность, которая живет в контексте совокупного корневого клиента. Это означает, что нет необходимости в репозитории Order, поскольку предполагается, что репозитории должны быть в расчете на один агрегатный корень. Таким образом, должен существовать только CustomerRepository, который должен знать, как сохранить Customer.Orders.
Я сам не сильно переживаю и вообще опускаю шаблон репозитория, а просто полагаюсь на NHibernate ORM. Богатая доменная модель, которая правильно отслеживает и отслеживает изменения состояния, намного важнее, чем способ, которым вы фактически отправляете операторы update/select sql.
Кроме того - подумайте дважды, прежде чем удалять вещи.
У вас есть хранилище для каждого объединенного корня, а не для объекта, таким образом, даже каскадное удаление дочерних элементов совокупного корня применимо в хранилище совокупного корня, поскольку оно все еще изолировано.
Не каскадное удаление или побочные эффекты для других агрегатных корней, координируйте эту логику на прикладном уровне.
Никогда не удаляйте клиента, клиент не удаляется, он становится неактивным или что-то в этом роде. Также, пожалуйста, не каскадно удаляйте заказы, это приведет вас в странные места, заказы всегда должны сохраняться при их обработке. Подумайте об отчетах для вашего приложения, так что выручка в 1,1 миллиона просто ушла, потому что вы решили каскадно удалить.
Ваша модель домена должна моделировать транзакционные операции вашего домена. Размещая Заказы на Клиенте, в вашей сущности Клиента вы говорите, что когда Клиент удаляется, то же самое происходит и с его Заказами.
Если у вас есть OrderIds на вашем клиенте, это другое. Чем у вас есть связь между Клиентом и Заказами. В этом случае вы говорите, что добавляя или удаляя из списка OrderIds на Customer, вы добавляете или удаляете ассоциации, а не добавляете или удаляете Orders.
Должна ли фактическая реализация репозиториев быть полностью изолирована друг от друга, даже если они в действительности имеют доступ к одной и той же базе данных?
Да, по большей части. Если вы решите сделать корни как для заказа, так и для клиента, вы говорите, что они независимы друг от друга и должны иметь возможность меняться независимо и одновременно. То есть, вам не нужно, чтобы изменения были транзакционными между ними. Если вы только делаете Клиента Агрегированным Корнем, и у него есть список заказов, теперь вы говорите, что сущность Клиента диктует, что происходит с Заказами, и изменение Клиента будет каскадно вносить изменения в его Заказы.
Теперь в вашем примере кажется, что у вас будут клиенты в качестве совокупных корней. И заказы как совокупные корни. Каждый со своим репо. У клиентов будет список идентификаторов OrderIds для моделирования связи "один ко многим". Если вы удалили клиента, вы можете опубликовать событие удаления клиента и очистить все, что связано с этим клиентом.