加载数据以使用CQRS和事件源来验证业务规则

时间:2016-05-20 08:26:51

标签: design-patterns cqrs event-sourcing

我有一个名为CreateItem的命令,它有一个要创建的项目(聚合根)的名称。现在我有一个业务规则,说明所有项目都必须唯一命名。

如果我使用事件源,则无法从写模型中查找,因此我需要将认为的内容称为投影,这将是一个表格其中包含每个" Item"的名称。它将根据ItemCreated事件保持最新。

现在,处理CreateItem命令的代码可以检查此表(并且应该使用查询吗?)。由于最终的一致性,这些数据完全有可能过时,所以我该如何处理?

1 个答案:

答案 0 :(得分:4)

  

现在我有一个业务规则,说明所有项目都必须具有唯一名称

您已进入称为集验证的问题空间。这意味着您需要在执行任何操作之前通过Greg Young阅读本文。

  

由于最终的一致性,这些数据完全有可能过时,所以我该如何处理?

我知道的答案只有三个

接受最终一致性,也就是说,更改要求。 (其中"聚合根"来自)的承诺的一部分是,您不仅要将模型与业务保持一致,而且还有一个将实际需求与想象的,并探索替代实施 - 不仅是模型,还有业务本身。

对于唯一性约束 - 如果聚合真诚地努力检查唯一性,并且您有一个允许您报告重复的流程(基于读取事件流),以及复制时的合理缓解策略确实出现了,模型拒绝所有重复名称真的那么重要吗?

您还需要明确您的模型负责相关财产。您的模型是决定名称是什么,还是只是被告知其他人做出了决定?在后一种情况下,您谈论的是事件,而不是命令,您需要一个不同的策略(流程管理器,也就是下游事件处理器)。

在设置验证时移动业务规则关系数据库非常好。如果您的事件存储恰好是关系数据库,那么您将用户名写入具有列约束的用户名表,该事务持久存储事件。领域知识泄露出您的模型,这有一些负面影响 - 您失去了将事件历史记录联合到多个数据库的能力。

理论上,关系数据库可以与事件存储分开,两阶段提交协调两者。我还没有找到任何当局描述他们很乐意拥有替代方案的情景。

更改聚合边界如果您需要集合中的事务一致性,那么集合是域模型的一部分,需要在某些聚合的边界内表示 - 例如, " ItemCatalog"也许。使用领域专家探索无处不在的语言可能有助于发现导致此约束的新聚合。

如果Item行为与名称紧密相关(那么,当名称当前以元音开头时,你的商品规则只能说DoubleThePrice?),那么Item实体本身就必须成为其中的一部分在相同的聚合中,您将需要接受对不同上下文的并发编辑中的争用。

无论您是在正确的模型中实现业务约束 - 即正确的有界上下文,也值得记住。例如,营销部门可能会非常关心项目名称的唯一性,而仓库并不关心。这表明你错过了普遍存在的语言的变化。请记住,如果概念对业务的不同部分意味着不同的东西,那么应该有不同的模型