用例:假设我有以下聚合
问题:如何向所有10个CustomerAggregate发送DisableCustomer
命令以更新其要禁用的状态?
customerState.enabled = false
解决方案:由于CQRS不允许写入方查询读取方以获取CustomerAggregate ID列表,我想到了以下内容:
CustomerRootAggregate
始终将所有CustomerAggregate
的ID作为json存储在数据库中。当DisableAllCustomers
收到CustomerRootAggregate
命令时,它将获取CustomerIds json并向所有子项发送DisableCustomer
命令,其中每个子项将在应用DisableCustomer
命令之前恢复其状态。但这意味着我必须保持CustomerIds json记录的一致性。 DisableCustomer
。但对于拥有数千名客户的数据库来说,这将是个问题。DisableAllCustomers
并从读取端获取所有ID,并发送带有写入端ID的DisableAllCustomers(ids)。哪种推荐方法或更好的方法?
答案 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聚合调度命令。
但是,通过这种方式做一些额外的工作。传统观点认为,您通常应该首先假设流程管理器方法是不必要的,并且只有在业务需要时才引入它。 "过早的自动化是所有邪恶的根源"或类似的东西。