1

我是 CQRS 的新手,在我的设计中需要关于以下情况的建议。一条命令更新聚合 A 的状态;因此需要使用交叉聚合计算方法的结果更新读取模型;此方法属于另一个聚合 B,该聚合 B 持有对聚合 A 的引用;该方法是聚合 B 和引用聚合 A 的状态的函数。调用此函数的正确位置在哪里?

我的考虑(可以跳过):

  • 命令处理程序更新聚合 A 的状态,技术上可以从存储库中获取聚合 B,对其调用计算并将结果放入域事件中;但是我认为获取聚合而不是被修改的聚合不是命令处理程序的工作,即使是出于阅读目的;此外,执行计算以发送事件而不是修改域的状态也不是命令处理程序的工作。
  • 域事件('聚合 A 已更新')仅包含聚合A的更新状态,聚合B的状态信息不足。读取模型的事件处理程序无法访问域模型,因此它既不能获取聚合B 也不在聚合 B 上调用所需的函数来更新读取模型。
  • 我知道命令所需的任何状态都在被修改的聚合外部,必须与命令一起传递。这样,应用服务在发送命令之前可以获取聚合 B 的状态(从读取模型中),并将其放入命令中。为此,我必须将函数从聚合 B 移动到某个服务,并在那里传递 A 和 B 的状态。这会使聚合 B 更加贫乏。加上上面提到的在命令处理程序中进行计算的问题。
  • 我读过有人建议只有读取模型感兴趣的任何计算都属于读取模型本身。因此,我的事件的读取模型处理程序将拥有执行计算所需的所有状态和行为。但是,这意味着我必须在查询端复制许多域模型概念;拥有完整的读取模型太复杂了。

我刚刚想到了以下解决方案:在域中,创建域事件“ Aggregate A updated ”的处理程序。它将获取聚合 B,对其调用计算方法,然后引发一个“聚合 B 函数结果已更改”事件,其中包含新的计算结果。然后读取模型能够从该事件中获取结果并更新自身。这样可以吗?

请注意,以防万一我没有使用事件溯源。

对这种情况的任何想法将不胜感激。谢谢!

更新: 使情况更加具体

我的聚合是Workers(聚合 B)和Group工人的 s(聚合 B)。Workers 和 Groups 是多对多的关系。想象一下 Group 和 Worker 都有一些Value财产。Worker'scalculateValue()是 Worker 的 Value 加上 Worker 参与的所有 Group 的 Value 的函数。上面描述的 Command 是Value针对某个 Group 进行修改的。结果,参与该组的所有工人将返回不同的结果calculateValue()

我想从读取模型中得到什么?我想要一个具有计算值的工人列表(已经考虑了工人所有组的值)。我什至不需要 Group 在读取端。如果我采用“在读取端进行计算”的方式,我需要组以及那里的整个关系结构。恐怕这将是一个不合理的并发症。

4

1 回答 1

2

命令处理程序更新聚合 A 的状态,技术上可以从存储库中获取聚合 B,对其调用计算并将结果放入域事件中;但是我认为获取聚合而不是被修改的聚合不是命令处理程序的工作,即使是为了阅读目的;此外,执行计算以发送事件而不是修改域的状态也不是命令处理程序的工作。

这是不行的,因为事件应该代表关于单个聚合发生的事实。

我知道命令所需的任何状态都在被修改的聚合外部,必须与命令一起传递。这样,应用服务在发送命令之前可以获取聚合 B 的状态(从读取模型中),并将其放入命令中。为此,我必须将函数从聚合 B 移动到某个服务,并在那里传递 A 和 B 的状态。这会使聚合 B 更加贫乏。加上上面提到的在命令处理程序中进行计算的问题。

您不应在事件中发送聚合状态。实际上,您不应该以任何其他方式查询聚合或使用聚合本身的内部和私有状态。在 CQRS 中,不会查询聚合。这是读取模型的目的。

我读过有人建议只有读取模型感兴趣的任何计算都属于读取模型本身。因此,我的事件的读取模型处理程序将拥有执行计算所需的所有状态和行为。但是,这意味着我必须在查询端复制许多域模型概念;拥有完整的读取模型太复杂了。

这是要走的路。但是,你到底复制了什么?聚合是否使用该计算的结果来接受或拒绝其任何命令?

如果是,那么它应该在聚合内完成,在命令执行时和可能随事件发送的最终结果,但前提是可以使用来自命令的数据和/或内部聚合的状态而不是通过交叉来完成计算聚合状态。如果一个聚合需要来自其他聚合的数据,那么这表明您的聚合边界可能是错误的。

如果不是,那么计算不应留在聚合内,而应仅在读取模型中。

在 CQRS 中,通过从读取模型中拆分写入,您也可以将计算拆分为写入和读取,但在某些情况下,两个模型共享计算。在这些情况下,您可以在一个类中提取计算并在两个模型中使用该类。

于 2017-09-13T12:36:07.837 回答