domain-driven-design - 为什么将命令和事件限制为一个集合? CQRS + ES + DDD

标签 domain-driven-design cqrs event-sourcing

请说明为什么在进行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/

相关文章:

postgresql - 用于事件溯源的关系数据库模式

c# - DDD\CQRS\Event Sourcing 和请求历史数据

domain-driven-design - 使用事件溯源时在哪里验证业务规则

domain-driven-design - 聚合根工厂方法可以返回命令而不是发布事件吗?

带两个参数的 Spring @EventListener

c# - MVC - Linq - 使用另一个表中的记录填充 List<T>

c# - 存储库类应该在哪里?

nhibernate - 使用 NHibernate 进行事件溯源

EventSourcing 和 DDD 实体事件

domain-driven-design - CQRS 聚合