大多数常见的ORM通过可达性实现持久性,作为默认对象图更改跟踪机制或可选。
通过可达性进行持久性意味着ORM将检查聚合根对象图并确定任何对象(也可间接)是否可访问,这些对象未存储在其身份映射(Linq2Sql)中或未设置其标识列(NHibernate)
在NHibernate中,这对应于cascade="save-update"
,对于Linq2Sql,它是唯一受支持的机制。他们同时执行这两项工作,但只为实现“添加”方面实现它,从聚合根图中删除的对象必须明确标记为删除。
在DDD上下文中,可以使用每个聚合根的存储库。 Aggregate Root中的对象可能只保留对其他Aggregate Roots的引用。由于可达性的持久性,可能会将其他根插入到数据库事件中,尽管根本没有调用相应的存储库!
考虑以下两个聚合根:Contract
和Order
。 Request
是Contract Aggregate的一部分。
对象图看起来像Contract->Request->Order
。每次承包商发出请求时,都会创建相应的订单。由于这涉及两个不同的聚合根,因此该操作由服务封装。
//Unit Of Work begins
Request r = ...;
Contract c = ContractRepository.FindSingleByKey(1);
Order o = OrderForRequest(r); // creates a new order aggregate
r.Order = o; // associates the aggregates
c.Request.Add(r);
ContractRepository.SaveOrUpdate(c);
// OrderAggregate is reachable and will be inserted
由于此操作发生在服务中,我仍然可以手动调用OrderRepository,但是我不会被强制使用!可达性持久性是聚合根中的一个非常有用的特性,但我认为强制我的聚合边界无法实现。
我在这里俯瞰什么吗?你会如何应对这种情况?
编辑:在NHibernate中,确实可以通过不将聚合根关联标记为cascade="save-update"
来强制执行聚合根边界。但是我坚持使用Linq2Sql。
答案 0 :(得分:2)
老实说,可达性的持久性并不是聚合根边界的问题。请记住,聚合根可以很好地引用彼此。通常,我会使用一个聚合根来创建另一个(例如Customer.CreateOrder
)。订单是客户的根,我仍然可以Customer.Orders[0].Comments = "Foo"
。
我不习惯改变领域模型而不是坚持改变,而是让它们消失。这不是一个真实的用例IMO。