更新CQRS中的查询部分

时间:2016-07-23 15:33:20

标签: architecture domain-driven-design cqrs

我读过很多关于CQRS的文章,还有一件小事我还是听不懂。到处写的有两个模型(它们甚至可能有两种不同类型的数据存储)。其中一个模型称为write模型,另一个模型称为read

这是流程:例如,写入模型进行一些更改,将这些更改存储到(自己的)DB中,然后触发事件。然后read模型,必须在此类事件上订阅,处理它并更新自己的投影这是正确的吗?如果是,那么它基本上意味着人们称之为read模型的东西不仅仅是从存储中读取。

我缺少什么? 主要问题是该部分负责更新投影/查询部分?

P.S。谢谢你的回复!现在组装拼图: - )

2 个答案:

答案 0 :(得分:2)

我理解它的方式......

写入/命令端是域模型,负责确保系统处于正确状态 - 如果使用DDD然后通过聚合。您加载聚合并应用某些行为。这是您的业务规则和行为所在的点。这也是您提出域事件的地方。这是一个很好的方法(特别是与数据库 你的事件)的事件采购相结合。但是,我不相信CQRS要求使用事件。例如,您可以只更新sql数据库中的某些状态。命令端用于保护域的不变量,

  

然后阅读模型,必须在这样的事件上订阅,处理它并更新自己的投影是正确的吗?

如果您正在使用活动,是的。但是,见下文......

  

如果是,则基本上意味着人们称之为读取模型的东西不仅仅是从存储中读取。

这取决于您的存储空间以及您的存储方式"创建"你的阅读模型。您可以订阅事件,然后更新某些数据库中的读取模型(可以是SQL数据库中的表,文档数据库中的文档),也可以更新内存中的对象模型。然后,您可以通过从数据库或内存模型中加载它们来查询这些读取模型。

但是,您还可以拥有无​​事件的CQRS 。在这种情况下,读取模型的概念可能只是一个数据库查询。即一个SQL查询。从与写入端相同的存储读取。

例如,API或网页请求进入,您对数据库执行查询,然后将结果返回给用户。此查询不会通过域模型。您仍然将读取与写入分开,您只是没有使用过事件。

  

主要问题是该部分负责更新投影/查询部分?

如果您正在使用活动,那么它将成为活动的订阅者。您将收听事件,然后更新您的阅读模型。这些实际的实现取决于您的架构。例如,如果使用EventStore,则客户端已经内置了对subscribers概念的支持。这些可以在一个简单的控制台应用程序中实现,例如,或在API内部实现。

此流程可能如下:

  • 应用程序启动
  • 订阅N个活动流
  • 收到活动时,更新数据库或内存模型

如果您不使用活动,则会有所不同。您的体系结构可能非常简单,以至于读取端只查询数据库(从命令端已经是最新的!)。

答案 1 :(得分:1)

  

如果是,那么它基本上意味着人们称之为阅读模式而不仅仅是阅读。

大部分都是正确的。

您在写模型中的实体具有包含写入方法的公共接口,但它们还包括复制当前状态(读取)的受限制接口。读模型中的实体具有包含读取方法的公共接口,但还包括替换当前状态的限制接口(写入)。

中间有一个进程,它使用受限制的接口来读取写入模型的状态,将其从写入优化的数据结构转换为读取优化的数据结构,然后使用受限制的接口进行写入读取模型的这个新状态。

我认为介绍商店的概念很有用,它与模型不同。写模型对写存储(也称为记录簿)进行更改,读模型使用读存储发布的状态来回答查询,受限接口用于链接两个存储;这创建了写模型和读模型之间的桥梁。

这种情况下的存储可能只是在内存中;例如,在java中,您可以通过将易失性句柄更新为读取优化数据结构来更新读取存储。数据模型中的方法只是抓取最近可用的数据结构版本,并继续使用该副本,直到查询完成(确保读取模型生成内部一致的查询结果)。

您通常希望中间的过程与写入模型本身的更新分离。它可能是事件驱动的(当我们看到域事件时,构建由该事件更改的读取优化数据结构的新副本,并发布它们)。它可能被安排(每隔一段时间,查询域事件的记录簿,并处理我们尚未见过的那些)。事件本身可能包含重建读取结构所需的所有状态(如果您在写入模型中使用事件源,这很可能),或者事件可能只是识别已更改的聚合,并且流程需要查询记录簿以查找所有相关状态。

很多选择,但他们倾向于遵循相同的基本模式。