我应该如何在聚合根之间强制执行关系和约束?

Eri*_*tas 11 domain-driven-design aggregate aggregateroot

关于DDD模型中两个聚合根之间的引用之间的关系,我有几个问题.请参阅下面的典型客户/订单模型.

在此输入图像描述

首先,聚合的实际对象实现之间的引用是否总是通过ID值而不是对象引用来完成?例如,如果我想要订单客户的详细信息,我需要获取CustomerId并将其传递给ICustomerRepository以获取客户,而不是设置Order对象以直接返回客户正确的客户?我很困惑,因为直接返回客户似乎会使编写代码对模型更容易,并且如果我使用像NHibernate这样的ORM,则设置起来并不困难.但我相当肯定这会违反聚合根/存储库之间的界限.

其次,对于两个聚合根,应该在何处以及如何对删除关系实施级联?例如,假设我希望在删除客户时删除所有关联的订单.ICustomerRepository.DeleteCustomer()方法应该不应该引用IOrderRepostiory吗?这似乎会破坏聚合/存储库之间的界限?我是否应该使用CustomerManagment服务来处理删除客户及其相关订单,这些订单将引用IOrderRepository和ICustomerRepository?在这种情况下,我如何确保人们知道使用服务而不是存储库来删除客户.这仅仅是为了教育他们如何正确使用模型?

Mar*_*ett 10

首先,聚合之间的引用是否应始终通过ID值而不是实际的对象引用来完成?

不是真的 - 尽管有些人会出于性能原因而做出改变.

例如,如果我想要订单客户的详细信息,我需要获取CustomerId并将其传递给ICustomerRepository以获取客户,而不是设置Order对象以直接返回客户正确的客户?

通常,您要为关系建模1侧(例如,Customer.OrdersOrder.Customer)进行遍历.另一个可以从适当的存储库中获取(例如,CustomerRepository.GetCustomerFor(Order)OrderRepository.GetOrdersFor(Customer)).

这是否意味着OrderRepository必须知道如何创建客户?这不会超出OrderRepository应该负责的范围......

OrderRepository会知道如何使用ICustomerRepository.FindById(int).你可以注射ICustomerRepository.有些人可能会对此感到不舒服,并选择将其放入服务层 - 但我认为这太过分了.存储库无法了解和使用彼此,这没有特别的原因.

我很困惑,因为直接返回客户似乎会使编写代码对模型更容易,并且如果我使用像NHibernate这样的ORM,则设置起来并不困难.但我相当肯定这会违反聚合根/存储库之间的界限.

总根允许持有至其他聚合的根引用.实际上,允许任何东西持有对聚合根的引用.但是,聚合根不能保存对不属于它的非聚合根实体的引用.

例如,Customer不能持有引用OrderLines- 因为OrderLines正确地属于Order聚合根上的实体.

其次,对于两个聚合根,应该在何处以及如何对删除关系实施级联?

如果(并且我强调,因为这是一个特殊的要求)实际上是一个用例,它表明Customer应该是你唯一的聚合根.在大多数现实世界中的系统,但是,我们不会真正删除一个Customer具有关联Order秒-我们可能会取消他们,把他们的Orders到合并Customer,等等-但不是彻头彻尾删除Order秒.

话虽这么说,虽然我认为它不是纯DDD,但大多数人会允许一些工作单元的宽容,你删除Orders然后Customer(如果Orders仍然存在则会失败).CustomerRepository如果你愿意的话,你甚至可以做这项工作(尽管我更愿意让自己更明确).允许孤儿Orders稍后(或不)清理也是可以接受的.用例在这里完全不同.

我是否应该使用CustomerManagment服务来处理删除客户及其相关订单,这些订单将引用IOrderRepository和ICustomerRepository?在这种情况下,我如何确保人们知道使用服务而不是存储库来删除客户.这仅仅是为了教育他们如何正确使用模型?

对于与存储库密切相关的东西,我可能不会去服务路线.至于如何确保服务被使用......你不把公众DeleteCustomerRepository.或者,如果删除Customer将留下孤立的Orders ,则抛出错误.