CQRS体系结构中的条件“创建”命令

时间:2018-11-28 22:14:00

标签: java domain-driven-design cqrs eventsource axon

我将简化我的问题:

我的LightsState API可以接收两种类型的输入:lightOn {lightId: ##}lightOff {lightId: ##}。 (AMQP输入,但此处无关)

这些输入可以很好地转换为2个命令:TurnLightOnCmdTurnLightOffCmd

这些命令将创建2个事件:LightTurnedOnEventLightTurnedOffEvent

这些事件将应用于Light Aggregate,并且持久的投影将成为state of the light

一切顺利,直到这里。

但是因为没有输入:create light,所以我不能从中输入CreateLightCmd。我只能在收到带有新CreateLightCmd的{​​{1}}输入时调用lightOn来创建lightId,然后在其上应用Light Aggregate

我不确定如何处理此问题以及是否遵循良好的CQRS惯例。 是否可以从命令方调用查询方以检查是否TurnLightOnCmd,然后根据需要首先调用light exists by id? 还是应该在Command端进行数据库查询,并保持Command和Query端分离? 还是对此有其他解决方案?

谢谢

2 个答案:

答案 0 :(得分:2)

  

可以从命令端调用查询端以检查light是否存在id,然后根据需要首先调用CreateLightCmd吗?

并非如此-引入了比赛条件,其后果可能不会使您满意。

评论: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)
}

答案 1 :(得分:0)

看看Udi Dahan的开创性文章“不要创建聚合根” [0]。关键点是:

  • 不要创建汇总根
  • 始终获取实体

这意味着发出命令时,应始终具有一个已将实际的聚合根实体初始化为默认状态的聚合。在您的情况下,默认状态为“熄灭”。您在此指示灯上执行命令,现在它处于“点亮”状态。现在,将其保存到数据库中并创建它。除非您的域关心LightCreatedEvent,否则不需要对其建模。

[0] http://udidahan.com/2009/06/29/dont-create-aggregate-roots/