CQRS 聚合

CQRS aggregates

我是 CQRS/ES 世界的新手,我有一个问题。我正在开发一个使用事件源和 CQRS 的发票 Web 应用程序。

我的问题是 - 据我了解,进入系统的新命令(比方说 ChangeLineItemPrice)应该通过域模型,以便它可以作为合法命令进行验证(例如,检查此行是否项目实际存在,价格不违反任何业务规则等)。如果一切顺利(命令未被拒绝)——然后创建并存储适当的事件(例如 LineItemPriceChanged)

我不太明白的是,在尝试应用命令之前,我如何首先将此聚合保存在内存中。如果系统中有一百万张发票,我是否应该在每次要应用命令时都回放整个历史记录?我是否总是在不进行任何验证的情况下保存事件,并在构建视图模型/投影时进行验证?

如果我误解了流程的任何部分,我将不胜感激您的反馈。

感谢您的帮助!

你并不孤单,这是一个普遍的误解。让我先回答验证部分:

在这种系统中有两种类型的验证。第一种是您在其中查找有效电子邮件地址、纯数字或必填字段的类型。这种类型甚至在命令发出之前就完成了。包含此类问题的命令不应作为命令提出(对于腰带和大括号,您可以在域端进行检查,但这不是域问题,最好避免这种情况)。

下一种类型的验证是域问题。这可能是您提到的检查价格是否在一组指定参数范围内的事情。这是一个业务人员会理解、会做并且能够表达的领域概念。

下一阶段是域应用状态更改并引发关联事件。然后这些将被保留并成功,为应用程序的其余部分发布。

所有这些都可以通过内存中的聚合来完成。这些操作与处理命令的域服务协调。它加载聚合,应用所有它的 过去的事件(或加载快照)然后发出命令。命令成功后,它会请求所有新的未提交事件并尝试保留它们。成功后它会发布新事件。

如您所见,它只加载特定聚合的事件。即使有很多事件,这个过程也快如闪电。如果性能有问题,可以采用一些策略,例如将聚合保留在内存中或快照。

关于验证事件的最后一点。因为它们只能由您的聚合生成,所以它们是值得信赖的。

如果您想了解更多详细信息,请查看我对 CQRS 和 ES 的概述here. And take a look at my post about how to build aggregate roots here

祝你好运 - 我希望他们有所帮助!

您必须将事件重播到 'rehydrate' 域聚合是正确的。但是您不必为所有发票重播所有事件。如果您将根聚合的实体 ID 存储在事件中,您可以 select 并重播具有相关 ID 的事件。

那么,如何找到相关的聚合根id呢?其中一个读取存储库应包含相关信息以根据一组搜索条件获取 id。