2017-09-13 28 views
1

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

我的注意事项(可以跳过):

  • 命令处理程序更新机组A的国家可以从技术上就可以了仓库,呼叫计算,并把结果在域事件获取骨料B;但是我相信这不是命令处理程序的工作,即使是为了阅读目的,也可以获取除被修改之外的集合。也不是命令处理程序的工作,只是为了发送事件而不是修改域的状态来执行计算。
  • 集合A引发的域事件('集合A更新')仅包含集合A的更新状态,集合B的状态信息不足。读取模型的事件处理程序无权访问域模型,因此它既不能获取聚集B,也不能在集合B上调用所需的函数来更新读取模型。
  • 我知道,被修改的聚合的外部命令需要的任何状态必须与该命令一起传递。通过这种方式,应用程序服务在发送命令之前可以获取聚合B的状态(从读取模型),并将其放入命令中。为此,我必须将函数从聚合B移动到某个服务,并传递A和B的状态。这会使聚合B更加贫血。加上上面提到的在命令处理程序中进行计算的问题。
  • 我读过的人认为任何只读模型感兴趣的计算都属于读模型本身。所以我的事件的读取模型的处理程序只需要处理所有需要的状态和行为来执行计算。但是这意味着我必须在查询端复制大部分域模型概念;拥有一个完整的阅读模型将会非常复杂。

我只是想到了以下解决方案:在域中,创建域事件“骨料更新”的处理程序。它将获取聚合B,调用其上的计算方法,然后提高'聚合B功能结果已更改'事件与新的计算结果。然后阅读模型能够从这个事件中获取结果并自行更新。这会好吗?

请注意,以防万一我不使用事件采购。

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

UPDATE:使局势更加具体

我的聚集体Worker S(骨料B)和Group小号工人(骨料B)。工人和团体是多对多的关系。想象一下,集团和工人都有一些Value财产。工人的calculateValue()是工人的价值加上工人参与的所有团体的价值的函数。上述命令正在修改某个团体的Value。因此,参加该组的所有工人将返回不同的结果calculateValue()

我想从阅读模型中得到什么?我想要一个带有计算值的工人列表(已经考虑了工人的所有组的值)。在阅读方面我甚至不需要Group。如果我在''的方式上进行'的计算,我需要组以及整个关系结构。恐怕这是一个不合理的并发症。

+0

你怎么能不需要在阅读方组?在用户界面中,如果没有阅读功能,您如何知道可用的群组,例如添加一个工作人员?如果您无法查询某个组向用户显示该信息,如何更新该组的“价值”? – TomW

+0

另外,记住聚合不能引用其他聚合,只能引用其ID。在任何情况下,使用CQRS,引用聚合对象在任何情况下都是无用的,因为它没有读取方法(聚合是只写对象)。 – TomW

+0

@TomW我正在讨论的读取模型不会被编辑工人和组关系的用户界面使用。我的理解是,你可以有很多阅读模型,不是吗?这个模型相当于被用作客户端组件,只需要工人和他们的计算值。 –

回答

2

命令处理程序更新机组A的国家可以从技术上存储库中取出聚集B,打电话的计算上,并把结果在域事件;但是我相信这不是命令处理程序的工作,即使是为了阅读目的,也可以获取除被修改之外的集合。也不是命令处理程序的工作,只是为了发送事件而不是修改域的状态来执行计算。

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

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

您不应该在事件中发送聚合状态。事实上,你不应该查询总结或以任何其他方式而是通过总结自身使用it't 内部和私人状态。 在CQRS中,聚合不被查询。这是一个阅读模型的目的。

我读过的人建议任何只读模型感兴趣的计算属于读模型本身。所以我的事件的读取模型的处理程序只需要处理所有需要的状态和行为来执行计算。但是这意味着我必须在查询端复制大部分域模型概念;拥有一个完整的阅读模型将会非常复杂。

这是要走的路。但是,无论如何你都会重复什么?是否由Aggregate使用该计算的结果来接受或拒绝其任何命令?

如果是,那么它应该在聚合内完成的,在沿着所述事件而发送的命令的执行时间和可能的最终结果只有在计算可以从指令和/或内部数据进行聚合的状态,而不是交叉聚合状态。如果聚合需要从其他数据集料那么这是你的骨料边界可能是错误的一个标志。

如果不是那么计算不应该留在聚合内,而只能在阅读模型中。

在CQRS,从读模式分裂写,你会分裂计算还撰写和阅读,但也有一些情况下,计算由两个车型共享。在这些情况下,您可以提取类中的计算和使用该类在两个模型。

+0

谢谢你的回复!您的问题的答案是_ Aggregate用来接受或拒绝其任何命令的计算结果_ _是'_no_'。我已经更新了我的问题,通过指定具体的聚合和它们之间的关系来扩展我的案例。尽管我认为这在概念上是正确的,但我仍然认为按照你的建议去做会很困难。再次期待您的意见。 –

+0

@PavelS你的用例仍然是一般的,你需要更具体。事实上,我们需要确切的计算方法以及您对它和哪里(读取,写入)的处理。 –

+0

现在我想我的理解在@ TomW's之后已经有了一些转变,并且您对总体的评论不适合查询。我可能希望得到一些半心半意的解决方案,但现在我看到CQRS是一件毫不妥协的事情:)必须重新审视整个设计。再次感谢你。 –