Domain driven design 我应该如何加强聚合根之间的关系和约束?

Domain driven design 我应该如何加强聚合根之间的关系和约束?,domain-driven-design,aggregate,aggregateroot,Domain Driven Design,Aggregate,Aggregateroot,关于DDD模型中两个聚合根之间的引用之间的关系,我有几个问题。请参阅下图所示的典型客户/订单模型 首先,聚合的实际对象实现之间的引用是否应该始终通过ID值而不是对象引用来完成?例如,如果我想要订单客户的详细信息,我需要获取CustomerId并将其传递到ICCustomerRepository以获取客户,而不是设置Order对象以直接返回客户正确吗?我很困惑,因为直接返回客户似乎会使编写模型代码变得更容易,而且如果我使用像NHibernate这样的ORM,设置起来也不会困难很多。但我相当肯定这

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

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

第二,应该在何处以及如何为两个聚合根强制执行级联删除关系?例如,假设我希望在删除客户时删除所有关联订单。ICCustomerRepository.DeleteCustomer()方法不应引用IOrderRepository,是吗?这似乎打破了聚合/存储库之间的界限?我是否应该使用CustomerManager服务来处理删除客户及其关联订单的操作,该服务将同时引用IOrderRepository和ICCustomerRepository?在这种情况下,我如何确保人们知道使用服务而不是存储库来删除客户。这仅仅是为了教育他们如何正确使用模型吗

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

不太可能——尽管有些人会因为性能原因而做出改变

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

通常,您需要为关系的一方建模(例如,
Customer.Orders
Order.Customer
)以进行遍历。另一个可以从相应的存储库中获取(例如,
CustomerRepository.GetCustomerFor(Order)
OrderRepository.GetOrdersFor(Customer)

这是否意味着OrderRepository必须了解如何创建客户?难道这不应该超出OrderRepository应该负责的范围吗

OrderRepository
将知道如何使用
icCustomerRepository.FindById(int)
。您可以插入
icCustomerRepository
。有些人可能对此感到不舒服,并选择将其放在服务层中——但我认为这太过分了。没有什么特别的原因使存储库不能相互了解和使用

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

允许聚合根保存对其他聚合根的引用。事实上,任何东西都可以保存对聚合根的引用。但是,聚合根不能持有对不属于它的非聚合根实体的引用

例如,
客户
不能持有对
订单行
的引用,因为
订单行
作为一个实体正确地属于
订单
聚合根目录

第二,应该在何处以及如何为两个聚合根强制执行级联删除关系

如果(我强调如果,因为这是一个特殊的需求)这实际上是一个用例,它表明
Customer
应该是您唯一的聚合根。然而,在大多数现实系统中,我们实际上不会删除与
订单
相关联的
客户
——我们可以停用他们,将他们的
订单
移动到合并的
客户
,等等——但不能彻底删除
订单

也就是说,虽然我不认为它是纯粹的DDD,但大多数人会允许在遵循一种工作单元模式时采取一些宽容的态度,即先删除
订单
s,然后删除
客户
(如果
订单
s仍然存在,则会失败)。如果您愿意,您甚至可以让
CustomerRepository
来做这项工作(尽管我自己更愿意让它更明确)。允许以后(或不)清理孤立的
订单
s也是可以接受的。用例在这里起着重要作用

我是否应该使用CustomerManager服务来处理删除客户及其关联订单的操作,该服务将同时引用IOrderRepository和ICCustomerRepository?在这种情况下,我如何确保人们知道使用服务而不是存储库来删除客户。这仅仅是为了教育他们如何正确使用模型吗


我可能不会为与存储库如此密切相关的东西选择服务路线。至于如何确保使用某项服务……您只需在
CustomerRepository
上不放置公共
Delete
。或者,如果删除
客户
会使订单成为孤立的
订单
s,则会引发错误。

另一个选项是使用ValueObject描述订单与客户ARs、VO之间的关联,其中将包含CustomerId和您可能需要的其他信息-姓名、地址等(类似于ClientInfo或CustomerData)

这有几个优点:

  • 您的AR是解耦的,现在可以进行分区,存储为事件流等
  • 按照ARs的顺序,你通常需要保留关于