问题描述
我尝试将事件溯源引入到我的项目中,但不确定如何以更少错误的方式完成特定的事情。
这是一个“会计”系统,但主要关注的是交易,而不是账户。问题是我收到了诸如提款或存款,授权保留被创建/减少/增加/过期/撤销,授权保留已解决(这意味着很快就会有提款事件)以及交易事件等事件详情。
在我的情况下,聚合根是一个事务。可以创建(通过授权保留或直接使用提款/存款事件)和更新。
这里有什么我不能完全理解的。我通过 authorization hold created
获得了第一个事件。在此事件中,我只有此授权保留的金额和密钥。关键来自外部系统,很明显。所以,我用 UUID4 生成了一个新的 TransactionId,创建一个新的聚合根,添加第一个事件,并将它持久化。接下来,我收到一个事件 withdrawal was created
。此事件具有金额、交易密钥和其他一些数据,并且可能 具有外部系统中具有授权保留引用的密钥。如果它没有这样的密钥,那么我只需生成一个新的 TransactionId 并存储一个新的聚合。但是,如果有这样的键,那么我需要加载在 authorization hold created event
期间创建的先前聚合。
问题是提款事件没有来自我的系统的聚合根 ID。如果我错了,请纠正我,但我考虑以下流程
- 检查
withdrawal created
事件是否引用了授权保留 - 如果引用不在事件中
- 使用
withdrawal created
事件创建新的交易聚合
- 使用
- 如果事件有参考
正确吗?
使问题更加抽象和通用。如果我没有在传入的消息中获得聚合根 ID,那么根据我基于传入数据的值构建的某些条件在事件存储中搜索特定的聚合根 ID 是否可以/有效?
解决方法
您不能/不应该从聚合中查询某些条件的事件存储,相反,客户端应首先查询读取端以查看相关聚合是否存在,然后将这些 ID 添加到命令中聚合。
,当我们看到“外部系统”的概念时,您肯定会来到集成领域。通常,内部有界上下文不希望与外部系统耦合。你的例子很好地说明了这个问题。您有来自外部系统的 id,在处理这些外部事件时需要将其映射到您的内部 id,并相应地生成内部命令。
这项工作是在我们称为“反腐败层”(Blue Book 中的模式)的地方完成的。它需要保留外部系统 ID 和内部 ID 之间的所有映射。
在最简单的情况下,ACL 只是一种读取模型。例如,当您收到已创建的授权保留并为该保留生成新 id 时,您将映射存储在某处,然后在收到提款事件时使用此存储来查询映射的 id。
但是,如果这个外部系统在您的上下文中是一个众所周知的概念(并且可能是),您可能希望将这些外部 ID 包含在您的域模型中,并将它们命名为 externalXXXId
。再说一次,通过将这些初始事件作为键值对投影到某个数据库,您将能够在收到第二个事件时找到此映射,然后相应地加载您的聚合(或创建一个新的聚合)。