首先,聚合之间的引用是否应该总是通过 ID 值而不是实际的对象引用来完成?
不是真的——尽管有些人会出于性能原因做出这种改变。
例如,如果我想要有关订单客户的详细信息,我需要获取 CustomerId 并将其传递给 ICustomerRepository 以获取客户,而不是设置订单对象以直接返回客户是否正确?
通常,您会为关系的一侧(例如,Customer.Orders
或Order.Customer
)建模以进行遍历。另一个可以从适当的存储库中获取(例如,CustomerRepository.GetCustomerFor(Order)
或OrderRepository.GetOrdersFor(Customer)
)。
这是否意味着 OrderRepository 必须知道如何创建客户?那岂不是超出了 OrderRepository 应该负责的范围……
会OrderRepository
知道如何使用ICustomerRepository.FindById(int)
. 您可以注入ICustomerRepository
. 有些人可能对此感到不舒服,并选择将其放入服务层——但我认为这太过分了。没有什么特别的原因,存储库不能相互了解和使用。
我很困惑,因为直接返回客户似乎会使针对模型编写代码更容易,并且如果我使用像 NHibernate 这样的 ORM,设置起来并不难。然而,我相当肯定这将违反聚合根/存储库之间的界限。
聚合根可以保存对其他聚合根的引用。事实上,任何东西都可以持有对聚合根的引用。但是,聚合根不能保存对不属于它的非聚合根实体的引用。
例如,Customer
不能持有对OrderLines
- 的引用,因为OrderLines
它正确地属于Order
聚合根上的实体。
其次,应该在哪里以及如何对两个聚合根执行级联删除关系?
如果(我强调如果,因为它是一个特殊的要求)实际上是一个用例,则表明它Customer
应该是您唯一的聚合根。然而,在大多数现实世界的系统中,我们实际上不会删除与sCustomer
相关联Order
的 a——我们可能会停用它们,将它们Order
的 s 移动到合并的 s 中Customer
,等等——但不会彻底删除Order
s。
话虽如此,虽然我不认为它是纯 DDD,但大多数人会在遵循工作单元模式时允许一些宽大处理,即删除Order
s 然后删除 s Customer
(如果Order
s 仍然存在,则会失败)。如果您愿意,您甚至可以让CustomerRepository
工作完成(尽管我更愿意自己更明确地说明)。Order
允许稍后(或不)清理孤立的 s 也是可以接受的。用例在这里发挥了重要作用。
我是否应该有一个 CustomerManagment 服务来处理删除客户及其关联的订单,这将引用 IOrderRepository 和 ICustomerRepository?在这种情况下,我如何确定人们知道使用服务而不是存储库来删除客户。这仅仅是教育他们如何正确使用模型吗?
对于与存储库密切相关的东西,我可能不会走服务路线。至于如何确保使用服务……您只是不要Delete
在CustomerRepository
. 或者,如果删除 aCustomer
会留下孤立Order
的 s,则会引发错误。