如何使用CQRS和事件采购来处理依赖于应用程序中现有记录的命令

时间:2016-01-30 06:09:03

标签: domain-driven-design cqrs event-sourcing

我们正在将CQRS与EventSourcing结合使用。

在我们的应用程序中,我们可以从ui添加资源(它是单个项目的业务术语),我们相应地发送命令来添加资源。

因此,我们在应用程序中存在x个以前添加的资源。 现在,我们有一种特殊类型的资源(我称之为SpecialResource)。 当我们添加此SpecialResource时,id需要与应用程序中的所有现有资源链接。 链接意味着此SpecialResource应具有现有资源的ID(guid)(List)列表。

在添加特殊内容之前,我们尝试在applcation中获取所有资源ID的解决方案 资源(即在触发AddSpecialResource命令之前)。 将这些List分配给SpecialResource,然后发送AddSpecialResource命令。

但我们并不认为这样做,因为根据cqrs命令不应该查询。 即命令不能依赖查询,因为查询可能有陈旧的记录。

如何在不查询应用程序中的现有记录的情况下实现此业务场景?

4 个答案:

答案 0 :(得分:1)

  

但我们并不认为这样做,因为根据cqrs命令不应该查询。即命令不能依赖查询,因为查询可能有陈旧的记录。

这不太对。

"命令"一直运行查询。如果您正在使用事件源,在大多数情况下您的命令查询 - "如果允许此命令,将生成什么事件?"

这与您描述的情况之间的区别在于聚合边界,在事件源域中,它是事件流的奇特名称。在处理命令时,允许聚合对其自己的事件流(也就是说,它自己的状态)运行查询。它是超出界限的其他聚合(事件流)。

实际上,这意味着如果 SpecialResource确实需要在事务上与其他资源ID保持一致,那么所有这些数据都需要是同一聚合的一部分,因此相同的事件流,从那一点开始的一切都非常简单。

因此,如果到目前为止您已经使用单独的流对资源进行建模,现在您需要使用SpecialResource按照您的描述进行工作,那么您要对域模型进行相当大的更改。

好消息:这可能不是你真正的要求。考虑一下你到目前为止所描述的内容 - 如果在SpecialResource之前一毫秒创建了resourceId:99652,那么它应该包含在SpecialResource的状态中,但是如果它是在一个毫秒后创建的,那么它就不应该了。那么,如果资源在错过SpecialResource之前创建了一毫秒,什么是业务成本

因为,先验,这听起来不像是太贵了。

更常见的是,真正的需求看起来更像是" SpecialResource需要包括在业务结束之前创建的所有资源ID,但实际上你需要在5分钟之后才需要SpecialResource关闭的业务。换句话说,您在此处获得了SLA,并且您可以使用该SLA更好地通知您的命令。

  

如何在不查询应用程序中的现有记录的情况下实现此业务场景?

转过来;运行查询,将查询结果(资源ID)复制到创建SpecialResource的命令中,然后调度要传递给域模型的命令。 CreateSpecialResource命令在其中包含正确的资源ID列表,因此聚合不需要担心如何发现该信息。

答案 1 :(得分:0)

很难说出你的数据库能够做什么,但添加“快照”最一致的方法是在数据库层,因为纯CQRS中没有其他常见的地方。 (有一些关于做CQRS + ES快照的文章,如果这是你实际尝试用SpecialResource实现的。)

一种方法可能是在AddSpecialResource命令到达时使用某种存储过程实现id列表(在数据库中)。

另一种方法是使用一些标记(时间戳)捕获“所有现有资源(最新)”,永远不删除旧资源,并在查询中添加“SpecialResource”条件,这将使用SpecialResource数据。

好的,另外一个选项(取决于您手头的情况)是始终使用同一个查询提供的id列表,这些查询为UI提供服务。这样,“所有资源”的定义将更改为“用户看到的所有资源(在某个时刻)”。

答案 2 :(得分:0)

我认为任何计算机系统都不会100%一致,因为生活不会,也不会像这样工作。显然我们都生活在过去,因为你的大脑需要时间来处理输入。

重点是您可以利用手头的信息尽力而为,但要确保您的系统能够平滑任何边缘。因此,如果您需要将一个或两个资源与SpecialResource相关联,那么您应该可以这样做。

即使您可以将您的SpecialResource与数据存储中的所有现有条目相关联,也就是说没有其他资源尚未输入系统这也需要联系起来。

像往常一样,这一切将取决于您的具体用例。这就是为什么流程经理及其状态使得人们能够按摩该状态直到流程完成。

我希望我没有误解你的问题:)

答案 3 :(得分:0)

你可以做两件事来解决这个问题:

  • 区分写入和读取模型。你知道什么是阅读模型,对吗?因此,相反,数据的“写模型”是数据结构和行为的组合,足以强制执行所有不变量并且由于每个执行的命令而生成一致的事件。

  • 不要采取规则,即“事件存储是单一的事实来源”。请考虑以下解释:ES是应用程序的所有事实的单一来源,但是,对于每个特定命令,您可以创建“写入模型”,这将提供足够的“真实性”以使此命令保持一致。