请说明为什么在进行CQRS,ES和DDD时同时修改多个聚合是一个坏主意。在任何情况下仍然可以吗?
例如,使用诸如PurgeAllCompletedTodos之类的命令。我希望此命令导致一个事件,该事件通过将IsActive设置为false来更新每个已完成的Todo聚合的状态。
为什么这不好?
我能想到的原因之一:
在更新域状态时,最好将事务限制为整个状态的明确定义的部分,这样在更新过程中只需要对该部分进行写锁定。这样做将允许并行地对不同聚合进行多次写入,这可以在某些极端繁重的情况下提高性能。
最佳答案
问题的答案在于“合计”的含义。
首先,我要说的不是修改“n”个聚合,而是修改“n”个实体。
聚合包含一个以上的实体,这只是一个事务概念,当您需要以事务方式修改应用程序中一个以上实体的状态时,可以使用聚合(模式)(全部修改或不修改)。
现在,为什么要用一个命令修改多个聚合呢?
如果您认为有此需要,请在执行其他任何操作之前检查聚合边界,以查看是否可以对其进行修改以消除对1命令->'n'聚合的需求。
聚合可以包含许多相同类型的实体,因此对于您的命令 PurgeAllCompletedTodos ,您还可以考虑将事务边界从单个 Todo 扩展到包含所有用户待办事项的聚合 UserTodosAggregate ,以及让它管理单个用户待办事项的所有命令。
这样,您可以在单个事务中修改用户的所有待办事项。
如果这仍然不能解决您的问题,因为说要清除应用程序中每个用户的所有已完成待办事项,您仍然需要向“n”个聚合发送命令,则聚合边界无济于事,因此我们可以考虑使用 AllApplicationTodosAggregate 来管理命令。
可能这不是最佳解决方案,因为正如您所说的那样,该命令将阻止应用程序的所有待办事项,但是,请始终检查它是否是一个不错的折衷方案(这部分的阻止在两个Blue中都得到了很好的解释。 DDD书和红皮书)。
如果我需要修改某些实体,而又不能将它们汇总在一起怎么办?
如前所述,由于事务的缘故,修改多个聚合的命令是不好的。如果您修改3聚合,首先是好的,然后关闭服务器怎么办?
在这种情况下,您要做的就是进行大量的单个修改,需要对其进行管理以防止系统不一致。
可以使用流程管理器来完成,流程管理器负责修改所有聚合,向它们发送正确的命令并管理失败(如果发生)。
聚合仍然接收它自己的命令,但是流程管理器负责以已知的方式发送它们(一次,一次并行,每次5次,您想要做什么)
因此,您可以制定一种策略来管理两个事务之间的失败,并做出类似以下的决定:“如果失败,请回滚直到现在为止所做的所有修改”(向每个聚合发送回滚命令),或者“如果操作失败重复一次”每30分钟3次,如果不起作用则回滚”,“如果失败,则为系统管理员创建通知”。
(很长的帖子,很抱歉,至少希望能对您有所帮助)
关于domain-driven-design - 为什么将命令和事件限制为一个集合? CQRS + ES + DDD,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32822302/