2011年12月29日 18:55 "@qiuriyuchen"的内容
终于知道我在说什么了,哈哈,这正是我想和你讨论的呀,我的意思就是没有必要全部一起保存,部分保存就可以了。先说在单机程序中吧,如果客户端持有的是副本,我觉得可以像这样order.EditOrderItem(orderItem),因为order ...

我的观点是:
1)Repository接口的输入参数或返回参数应该是聚合根,而不能是聚合内的某个实体;
2)如果Repository接口的参数可以随便设计,那Repository已经和DAO五差别了,这其实就是把Repository当作DAO来用了,纯粹是把他当作是一个更新数据或去数据的接口了。而实际上DDD中的Repository面向的一定是聚合根,就是指接收的参数或返回的都应该是聚合跟;这样才符合Repository是一个生活在内存中的集合的定义;
3)在Order类中访问Repository是不可取的;我极不赞成这样的做法;而基于事件驱动的思路我比较赞同;Domain Object的职责是告诉别人我发生了什么即可,而不能去请求别人我要做什么,比如请求Repository帮他把某个OrderItem给持久化一下;
4)再给你举个列子说明一下为什么不能只保存聚合的部分实体;比如一个订单,目前最多只能容下最多一个OrderItem了,然后A,B两个人同时取出这个订单,这是对于A,B来说,他们都知道还能再新增一个OrderItem,于是他们先后新增了一个OrderItem,当A新增一个OrderItem时,数据库锁住Order,然后更新成功,解锁;然后B新增了一个OrderItem,数据库再锁,然后保存成功,然后解锁;为什么后面的OrderItem也能保存成功?因为数据库是不具备业务逻辑去判断当前这个OrderItem能否被新增的,只有内存中的Order才知道;数据库只能确保不能有两个人同时改同一个Order;基于上面的情况,数据库最后就会出现一个Order包含了过多的OrderItem的情况,从而也就违反了不变性约束;
5)从逻辑的角度,你想想你希望一个东西的状态不能违反某个不变性,但是允许多个人以先后的顺序在不同的内存空间部分的添加或删除其子实体,并且可以允许部分持久化;要知道数据库是不具备聚合所规定的不变性约束规则的,它只知道帮你锁数据,或者接收新的数据而已;只是一个帮你管理数据的容器;再强调一次Aggregate is a unit of data changes,要做到unit,不只是在内存中要通过聚合的方式来控制,也需要在数据库中也确保其被更新时是以一个整体的姿态被更新的,而不能只更新部分;那么因为数据库里没有所谓的聚合的概念,那如何确保数据库里某些实际上是“聚合”数据也能作为一个单元被更新呢?只有一个办法,那就是任何人更新这些数据时,都是完整替换,而不是部分替换;从而才引出为什么整个聚合要整个完全覆盖数据库里的数据的原因。

当然,除非你每次在保存任何一个聚合之前,都先去数据库查询出最新的Order信息,然后和你当前内存中将要保存的Order进行比较,判断当前最新的Order中的你新增的那个OrderItem能否被添加进Order;但是要对每个聚合都做这样的处理不是很麻烦吗?

另外,从理论上讲,这样的做法也是逻辑性不严密的。因为你如何确保当你在保存Order前从数据库查询出来Order,在等你做了“你内存中Order”与“数据库里新查出来的Order”的对比之后,然后再做保存的那段时间内别人没有修改过数据库里的Order呢?除非你在查询出Order之后立马再用锁锁住数据库里的Order。这样做不是非常麻烦吗?

还有,如果我不是用数据库来存储的,比如是用MongoDB来存储的,或者其他一些不支持锁的存储介质,那如何确保这些存储介质里存放的数据是具备一致性的呢?或者更极端的情况如果我一个聚合是放在两个分布式的数据库中呢?是不是要用分布式锁了?那我如果一个聚合的一部分放在文件,一部分放在数据库里,那你如何锁?

在理解一下什么是Aggregate is a unit of data changes.Unit就是数据更改的原子单元,原子不能被部分更新,原子可以看成是一个值对象,值对象不可更新,只能直接整个替换;

这一段时间用代码实践了一下,有了新想法,Repository确实不应该有操作非根对象的方法,Repository的意义就是要向领域层屏蔽数据库的存在,让领域层像使用集合一样来存放对象(持久化),面向领域越纯粹,Repository的实现越复杂,比如更新聚合内非根,必须通过根实体来更新内存,如果要保存到数据库,则可以用Repository来保存实体根,当然也可以几步业务操作之后再持久化根,Repository实现局部更新或者全部更新,取决于Repository,如果是局部更新则需要做一些对比,这些都是Repository的责任,还有比如对象的延迟加载,也是Repository,要让领域层很纯净,只关心领域,Repository要完全为关系数据库和对象之间的映射以及由些带来的问题买单,比如刚才说道的局部更新和懒加载。
我做的示例程序没用框架,懒加载集合用的非空判断,对象用的代理对象。局部更新不用框架自己实现比较麻烦,考虑用把关联的数据clear,再insert,关联数据量不大,这样领域层就比较纯净了,只是Reposioty的实现有点不太厚道。