在CQRS / Eventsourcing中,这是父母修改所有孩子的状态的最佳方法吗?

时间:2015-11-18 00:31:11

标签: cqrs event-sourcing

用例:假设我有以下聚合

  • 根聚合 - CustomerRootAggregate(管理每个CustomerAggregate)
  • 根聚合的子聚合 - CustomerAggregate(有10个客户)

问题:如何向所有10个CustomerAggregate发送DisableCustomer命令以更新其要禁用的状态?

customerState.enabled = false

解决方案:由于CQRS不允许写入方查询读取方以获取CustomerAggregate ID列表,我想到了以下内容:

  1. CustomerRootAggregate始终将所有CustomerAggregate的ID作为json存储在数据库中。当DisableAllCustomers收到CustomerRootAggregate命令时,它将获取CustomerIds json并向所有子项发送DisableCustomer命令,其中每个子项将在应用DisableCustomer命令之前恢复其状态。但这意味着我必须保持CustomerIds json记录的一致性。
  2. 客户端(浏览器 - 用户界面)应始终发送CustomerIds列表以应用DisableCustomer。但对于拥有数千名客户的数据库来说,这将是个问题。
  3. 在REST API层中检查命令DisableAllCustomers并从读取端获取所有ID,并发送带有写入端ID的DisableAllCustomers(ids)。
  4. 哪种推荐方法或更好的方法?

1 个答案:

答案 0 :(得分:2)

  
      
  • 根聚合 - CustomerRootAggregate(管理每个CustomerAggregate)
  •   
  • 根聚合的子聚合 - CustomerAggregate(有10个客户)
  •   

对于初学者来说,语言" child aggregate"有点混乱。您的模型包括父母"直接引用"孩子的实体"实体,那么这两个实体必须是同一聚合的一部分。

但是,您可能拥有每个客户的Customer聚合,以及管理Id集合的CustomerSet聚合。

  

如何向所有10个CustomerAggregate发送DisableCustomer命令以更新其要禁用的状态?

通常的答案是您运行查询以获取要禁用的客户集,然后向每个客户发送disableCustomer命令。

因此,3和2都是合理的答案,需要注意的是,如果某些DisableCustomer命令失败,您需要考虑您的要求。

2尤其具有诱惑力,因为它清楚地表明客户端(人工操作员)正在描述一个任务,然后应用程序通过域模型运行将其转换为命令。

试图打包"成千上万"客户ID进入消息可能是一个问题,但对于几个用例,您可以找到一种方法来缩小它。例如,如果任务是"禁用所有",则客户端可以向应用程序发送有关如何重新创建" all"的说明。集合 - 即:"针对此特定版本的集合运行此查询"描述了明确禁用的客户列表。

  

当CustomerRootAggregate接收到CommandAllCustomers命令时,它将获取CustomerIds json并向所有子项发送DisableCustomer命令,其中每个子项将在应用DisableCustomer命令之前恢复它的状态。但这意味着我必须保持CustomerIds json记录的一致性。

这接近一个正确的想法,但并不完全存在。您将命令分派给集合聚合。如果它接受该命令,则会生成一个描述要禁用的客户ID的事件。此域事件将作为集合聚合的事件流的一部分保留。

使用负责创建流程管理器的事件处理程序订阅这些事件。此进程管理器是另一个事件源状态机。它看起来有点像聚合,但它会响应事件。当一个事件传递给它时,它会更新自己的状态,在当前事务中保存这些事件,然后为每个Customer聚合调度命令。

但是,通过这种方式做一些额外的工作。传统观点认为,您通常应该首先假设流程管理器方法是不必要的,并且只有在业务需要时才引入它。 "过早的自动化是所有邪恶的根源"或类似的东西。