应用命令后调用交叉聚合计算函数更新读取模型
Calling cross-aggregate calculation function to update read model after a command applied
我是 CQRS 的新手,需要针对我设计中的以下情况提供建议。命令更新聚合 A 的状态;读取模型需要用交叉聚合计算方法的结果进行更新;此方法属于另一个聚合 B,它持有对聚合 A 的引用;该方法是聚合 B 和引用的聚合 A 的状态函数。调用此函数的正确位置在哪里?
我的考虑(可跳过):
- 更新聚合 A 状态的命令处理程序可以从技术上从存储库中获取聚合 B,对其调用计算并将结果放入域事件中;但是,我认为获取聚合而不是被修改的聚合不是命令处理程序的工作,即使是出于阅读目的;同样,执行计算只是为了发送事件而不是修改域的状态也不是命令处理程序的工作。
- 聚合A引发的域事件('聚合A已更新')仅包含聚合A的更新状态,聚合B的状态信息不足。读取模型的事件处理程序无法访问域模型,因此它既不能获取聚合 B,也不能调用聚合 B 上的所需函数来更新读取模型。
- 我知道命令所需的任何状态(在正在修改的聚合外部)都必须随命令一起传递。这样,应用程序服务在发送命令之前,可以获取聚合 B 的状态(从读取模型),并将其放入命令中。为此,我必须将函数从聚合 B 移动到某个服务,并将 A 和 B 的状态传递到那里。这会使聚合 B 更加贫血。加上上面提到的在命令处理程序中进行计算的问题。
- 我读到过有人建议只对读取模型感兴趣的任何计算都属于读取模型本身。因此,我的事件的读取模型的处理程序将拥有执行计算所需的所有状态和行为。然而,这意味着我必须在查询端复制大部分领域模型概念;拥有成熟的读取模型太复杂了。
我刚刚想到了以下解决方案:在域内,创建域事件“Aggregate A updated”的处理程序。它会获取聚合 B,对其调用计算方法,然后引发“聚合 B 函数结果已更改”事件,其中包含新的计算结果。然后读取模型能够从这个事件中获取结果并更新自身。这样可以吗?
请注意以防万一我没有使用事件溯源。
如果您对这种情况有任何想法,我们将不胜感激。谢谢!
更新:使情况更具体
我的聚合是 Worker
s(聚合 B)和 Group
s 工人(聚合 B)。 Worker 和 Groups 是多对多的关系。想象一下,一个 Group 和一个 Worker 都有一些 Value
属性。 Worker 的 calculateValue()
是 Worker 的值加上该 Worker 参与的所有组的值的函数。上述命令正在修改某些组的 Value
。结果,所有参与该组的 Worker 将 return 不同的结果 calculateValue()
。
我想从读取模型中得到什么?我想要一个具有计算值的工人列表(已经考虑了工人所有组的值)。我什至不需要 Group 在阅读方面。如果我采用“在读取端进行计算”的方式,我需要组以及那里的整个关系结构。恐怕这会是一个不合理的并发症。
Command handler updating state of aggregate A could technically fetch aggregate B from the repository, call calculation on it and put result in the domain event; however I believe it's not command handler's job to fetch aggregates other than one being modified, even for reading purposes; also it's not command handler's job to perform calculations just to send with events rather than modify the state of domain.
这不行,因为事件应该代表与单个聚合有关的事实。
I know that any state needed by command which is external to the aggregate being modified must be passed along with the command. This way the application service, before sending the command, could fetch state of aggregate B (from read model), and put it in the command. For that I would have to move the function from aggregate B to some service and pass there states of both A and B. That would make aggregate B more anemic. Plus the above mentioned problem with doing calculations within command handler.
您不应在事件中发送聚合状态。事实上,您不应该查询聚合或以任何其他方式而不是通过聚合本身使用它 internal 和 private 状态。 在 CQRS 中不查询聚合。这就是阅读模型的目的。
I've read people suggesting that any calculations that only read model is interested in belong to the read model itself. So the read model's handler of my event would just have at its disposal all needed state and behavior to perform calculations. However that would mean I have to duplicate much of the domain model concepts at the query side; it would be too complex to have a full-blown read model.
这是要走的路。然而,你到底复制了什么?聚合是否使用该计算的结果来接受或拒绝其任何命令?
如果是,那么它应该在聚合内部完成,在命令执行时并且可能最终结果随事件一起发送,但前提是可以使用来自命令 and/or 内部聚合状态的数据,而不是交叉聚合状态。如果一个聚合需要来自其他聚合的数据,那么这表明您的聚合边界可能是错误的。
如果不是,则计算不应保留在聚合内部,而应仅保留在读取模型中。
在 CQRS 中,通过将写入模型与读取模型分开,您也可以将计算拆分为写入和读取,但在某些情况下,两个模型共享一个计算。在这些情况下,您可以在 Class 中提取计算并在两个模型中使用 Class。
我是 CQRS 的新手,需要针对我设计中的以下情况提供建议。命令更新聚合 A 的状态;读取模型需要用交叉聚合计算方法的结果进行更新;此方法属于另一个聚合 B,它持有对聚合 A 的引用;该方法是聚合 B 和引用的聚合 A 的状态函数。调用此函数的正确位置在哪里?
我的考虑(可跳过):
- 更新聚合 A 状态的命令处理程序可以从技术上从存储库中获取聚合 B,对其调用计算并将结果放入域事件中;但是,我认为获取聚合而不是被修改的聚合不是命令处理程序的工作,即使是出于阅读目的;同样,执行计算只是为了发送事件而不是修改域的状态也不是命令处理程序的工作。
- 聚合A引发的域事件('聚合A已更新')仅包含聚合A的更新状态,聚合B的状态信息不足。读取模型的事件处理程序无法访问域模型,因此它既不能获取聚合 B,也不能调用聚合 B 上的所需函数来更新读取模型。
- 我知道命令所需的任何状态(在正在修改的聚合外部)都必须随命令一起传递。这样,应用程序服务在发送命令之前,可以获取聚合 B 的状态(从读取模型),并将其放入命令中。为此,我必须将函数从聚合 B 移动到某个服务,并将 A 和 B 的状态传递到那里。这会使聚合 B 更加贫血。加上上面提到的在命令处理程序中进行计算的问题。
- 我读到过有人建议只对读取模型感兴趣的任何计算都属于读取模型本身。因此,我的事件的读取模型的处理程序将拥有执行计算所需的所有状态和行为。然而,这意味着我必须在查询端复制大部分领域模型概念;拥有成熟的读取模型太复杂了。
我刚刚想到了以下解决方案:在域内,创建域事件“Aggregate A updated”的处理程序。它会获取聚合 B,对其调用计算方法,然后引发“聚合 B 函数结果已更改”事件,其中包含新的计算结果。然后读取模型能够从这个事件中获取结果并更新自身。这样可以吗?
请注意以防万一我没有使用事件溯源。
如果您对这种情况有任何想法,我们将不胜感激。谢谢!
更新:使情况更具体
我的聚合是 Worker
s(聚合 B)和 Group
s 工人(聚合 B)。 Worker 和 Groups 是多对多的关系。想象一下,一个 Group 和一个 Worker 都有一些 Value
属性。 Worker 的 calculateValue()
是 Worker 的值加上该 Worker 参与的所有组的值的函数。上述命令正在修改某些组的 Value
。结果,所有参与该组的 Worker 将 return 不同的结果 calculateValue()
。
我想从读取模型中得到什么?我想要一个具有计算值的工人列表(已经考虑了工人所有组的值)。我什至不需要 Group 在阅读方面。如果我采用“在读取端进行计算”的方式,我需要组以及那里的整个关系结构。恐怕这会是一个不合理的并发症。
Command handler updating state of aggregate A could technically fetch aggregate B from the repository, call calculation on it and put result in the domain event; however I believe it's not command handler's job to fetch aggregates other than one being modified, even for reading purposes; also it's not command handler's job to perform calculations just to send with events rather than modify the state of domain.
这不行,因为事件应该代表与单个聚合有关的事实。
I know that any state needed by command which is external to the aggregate being modified must be passed along with the command. This way the application service, before sending the command, could fetch state of aggregate B (from read model), and put it in the command. For that I would have to move the function from aggregate B to some service and pass there states of both A and B. That would make aggregate B more anemic. Plus the above mentioned problem with doing calculations within command handler.
您不应在事件中发送聚合状态。事实上,您不应该查询聚合或以任何其他方式而不是通过聚合本身使用它 internal 和 private 状态。 在 CQRS 中不查询聚合。这就是阅读模型的目的。
I've read people suggesting that any calculations that only read model is interested in belong to the read model itself. So the read model's handler of my event would just have at its disposal all needed state and behavior to perform calculations. However that would mean I have to duplicate much of the domain model concepts at the query side; it would be too complex to have a full-blown read model.
这是要走的路。然而,你到底复制了什么?聚合是否使用该计算的结果来接受或拒绝其任何命令?
如果是,那么它应该在聚合内部完成,在命令执行时并且可能最终结果随事件一起发送,但前提是可以使用来自命令 and/or 内部聚合状态的数据,而不是交叉聚合状态。如果一个聚合需要来自其他聚合的数据,那么这表明您的聚合边界可能是错误的。
如果不是,则计算不应保留在聚合内部,而应仅保留在读取模型中。
在 CQRS 中,通过将写入模型与读取模型分开,您也可以将计算拆分为写入和读取,但在某些情况下,两个模型共享一个计算。在这些情况下,您可以在 Class 中提取计算并在两个模型中使用 Class。