我会简化我的问题:
我的 LightsState API 可以接收 2 种类型的输入:lightOn {lightId: ##}
和 lightOff {lightId: ##}
。 (AMQP 输入,但与此处无关)
这些输入可以很好地转换为 2 个命令:TurnLightOnCmd
和 TurnLightOffCmd
。
这些命令将创建 2 个事件:LightTurnedOnEvent
和 LightTurnedOffEvent
。
这些事件将应用于Light Aggregate
,持久投影将是灯光状态
。
到这里为止一切都很好。
但是因为没有输入:create light
,我无法从中创建CreateLightCmd
。当我收到带有新 lightId
的 lightOn
输入来创建 Light Aggregate
时,我只能调用 CreateLightCmd
然后还应用 TurnLightOnCmd
。
我不知道如何处理这个问题并遵循良好的 CQRS 实践。 是否可以从命令端调用查询端来检查 id 是否存在灯光,然后在需要时首先调用 CreateLightCmd ? 或者我应该从命令端进行数据库查询并保持命令端和查询端解耦? 或者还有其他解决方案吗?
谢谢
最佳答案
Is it ok to call the Query side from Command side to check if light exists by id and then invoke CreateLightCmd first if needed?
并非如此 - 这会引入竞争条件,其后果可能不会让您高兴。
回顾:DDD+CQRS+ES 在架构上与单独的 DDD 非常相似。基本概念是我们将信息保存到我们的存储设备(也称为“数据库”)中。该模型在从数据库加载当前状态的进程中运行,使用命令计算新状态,然后将该新状态存储在数据库中。
当我们进行事件溯源时,同样的模式也适用 - 我们从用于写入的数据库中读取历史记录,计算新事件,并将这些事件附加到历史记录中。
但是:创建模式很奇怪。
当我们尝试查询以前从未见过的标识符的历史记录时,我们将得到 null 或 None
或其中没有事件的历史记录,或类似的东西。
令人惊讶的是:这很好。
对于您的用例,您不一定需要 CreateLightCmd
- 相反,您希望在获得其他命令之一时生成一个新的 LightCreatedEvent
应该隐式地创建光。
伪代码:
TurnLightOn (cmd) {
history = getHistory(cmd.lightId)
if (history.isEmpty) {
history.append(LightCreatedEvent.from(cmd))
}
history.append(LightTurnedOnEvent.from(cmd))
save(cmd.lightId, history)
}
关于java - CQRS 架构中的条件 `create` 命令,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53528912/