本文介绍了如何在聚合根之间强制执行关系和约束?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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





例如,如果我想要有关订单客户的详细信息,我需要获取CustomerId并将其传递给ICustomerRepository以获取客户,而不是设置Order对象以直接返回客户吗?我很困惑,因为直接返回客户似乎会使针对模型的代码编写更加容易,并且如果我使用的是NHibernate之类的ORM,则设置起来也不会很困难。但是我相当确定这将违反聚合根目录/存储库之间的界限。



第二,在哪里以及如何对两个聚合根目录执行删除关系的级联?例如,说我希望在删除客户时删除所有关联的订单。 ICustomerRepository.DeleteCustomer()方法应该不引用IOrderRepostiory吗?好像那样会打破聚合/存储库之间的界限?我是否应该有一个CustomerManagment服务来处理删除客户及其关联的同时引用IOrderRepository和ICustomerRepository的订单?在这种情况下,我如何确定人们知道使用服务而不是使用存储库来删除客户。仅仅是为了教育他们如何正确使用模型?

解决方案

不是真的-尽管有些是出于性能原因会进行更改。

通常,您会模拟关系的1面(例如, Customer.Orders Order.Customer )进行遍历。另一个可以从适当的存储库中获取(例如, CustomerRepository.GetCustomerFor(Order) OrderRepository.GetOrdersFor(Customer))。

OrderRepository $ c>会知道如何使用 ICustomerRepository.FindById(int)。您可以注入 ICustomerRepository 。有些人可能对此感到不舒服,因此选择将其放入服务层-但我认为这太过分了。存储库之间不存在彼此不了解和使用的特殊原因。

聚合根允许保留对其他聚合根的引用。实际上,任何东西都可以保留对聚合根的引用。聚合根不能包含对不属于它的非聚合根实体的引用。



例如, Customer 无法保存对 OrderLines 的引用-因为 OrderLines 正确地属于 Order 聚合根。

If (我强调,因为这是一个特殊的要求),实际上是两个在一个用例中,这表明 Customer 应该是您唯一的总根。但是,在大多数实际系统中,我们实际上不会删除 Order Customer c $ c> s-我们可能会停用它们,将其 Order s移至合并的 Customer 等,但是-不必反复删除 Order s。



话虽这么说,但我不认为这是纯粹的- DDD,大多数人会允许一些宽大的工作,遵循一种工作单元模式,即先删除 Order s然后删除 Customer (如果 Order 仍然存在,则失败)。如果愿意,您甚至可以让 CustomerRepository 来完成工作(尽管我希望自己更明确地进行说明)。允许稍后(也可以不)清理孤立的 Order 也是可以接受的。用例在这里起到了很大的作用。

我可能不会为某些事情走一条服务路线,所以与存储库密切相关。至于如何确保使用服务...您只是不要在 CustomerRepository 删除 >。或者,如果删除 Customer 会留下孤立的 Order s,则抛出错误。


I have a couple questions regarding the relationship between references between two aggregate roots in a DDD model. Refer to the typical Customer/Order model diagrammed below.

First, should references between the actual object implementation of aggregates always be done through ID values and not object references? For example if I want details on the customer of an Order I would need to take the CustomerId and pass it to a ICustomerRepository to get a Customer rather then setting up the Order object to return a Customer directly correct? I'm confused because returning a Customer directly seems like it would make writing code against the model easier, and is not much harder to setup if I am using an ORM like NHibernate. Yet I'm fairly certain this would be violating the boundaries between aggregate roots/repositories.

Second, where and how should a cascade on delete relationship be enforced for two aggregate roots? For example say I want all the associated orders to be deleted when a customer is deleted. The ICustomerRepository.DeleteCustomer() method should not be referencing the IOrderRepostiory should it? That seems like that would be breaking the boundaries between the aggregates/repositories? Should I instead have a CustomerManagment service which handles deleting Customers and their associated Orders which would references both a IOrderRepository and ICustomerRepository? In that case how can I be sure that people know to use the Service and not the repository to delete Customers. Is that just down to educating them on how to use the model correctly?

解决方案

Not really - though some would make that change for performance reasons.

Generally, you'd model 1 side of the relationship (eg., Customer.Orders or Order.Customer) for traversal. The other can be fetched from the appropriate Repository (eg., CustomerRepository.GetCustomerFor(Order) or OrderRepository.GetOrdersFor(Customer)).

The OrderRepository would know how to use an ICustomerRepository.FindById(int). You can inject the ICustomerRepository. Some may be uncomfortable with that, and choose to put it into a service layer - but I think that's overkill. There's no particular reason repositories can't know about and use each other.

Aggregate roots are allowed to hold references to other aggregate roots. In fact, anything is allowed to hold a reference to an aggregate root. An aggregate root cannot hold a reference to a non-aggregate root entity that doesn't belong to it, though.

Eg., Customer cannot hold a reference to OrderLines - since OrderLines properly belongs as an entity on the Order aggregate root.

If (and I stress if, because it's a peculiar requirement) that's actually a use case, it's an indication that Customer should be your sole aggregate root. In most real-world systems, however, we wouldn't actually delete a Customer that has associated Orders - we may deactivate them, move their Orders to a merged Customer, etc. - but not out and out delete the Orders.

That being said, while I don't think it's pure-DDD, most folks will allow some leniency in following a unit of work pattern where you delete the Orders and then the Customer (which would fail if Orders still existed). You could even have the CustomerRepository do the work, if you like (though I'd prefer to make it more explicit myself). It's also acceptable to allow the orphaned Orders to be cleaned up later (or not). The use case makes all the difference here.

I probably wouldn't go a service route for something so intimately tied to the repository. As for how to make sure a service is used...you just don't put a public Delete on the CustomerRepository. Or, you throw an error if deleting a Customer would leave orphaned Orders.

这篇关于如何在聚合根之间强制执行关系和约束?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

09-03 09:42