11

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

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

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

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

谢谢你的帮助!

4

2 回答 2

20

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

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

下一种类型的验证是当它一个域问题时。它可能是你提到的那种你检查价格是否在一组指定参数内的事情。这是业务人员能够理解、执行并能够表达的领域概念。

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

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

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

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

如果您想了解更多详细信息,请在此处查看我对 CQRS 和 ES 的概述。看看我关于如何在这里建立聚合根的帖子。

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

于 2015-07-16T19:48:02.660 回答
1

您必须重播事件以“补充”域聚合是正确的。但您不必重播所有发票的所有事件。如果将根聚合的实体 id 存储在事件中,则只需选择并重播具有相关 id 的事件。

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

于 2015-11-23T16:03:10.663 回答