【发布时间】:2017-06-27 12:01:12
【问题描述】:
因此,我在聚合根目录上触发命令,并且由于该命令而发生了大约 10 个事件。这些事件是内部事件,由于外部系统需要聚合这些事件,我决定进行投影(基本上是阅读投影)。为了从 10 个事件(内部)到 1 个事件(外部)进行此预测,我必须应用一些业务规则(有关事件合并的业务规则)。我应该把这些规则放在哪里,因为它看起来像是域的一部分,但我正在创建内部事件的预测?
基本上由于投影逻辑是域的一部分,我应该将它保存在聚合中并在进行投影的代码中调用它吗?
更新
所以,在一个聚合根中,我有例如3 个事件(内部)作为对一个命令 (aggregate.createPaintandwashatsametime(id, red)) 的响应,该命令发送到聚合根并通过所有聚合根实体传播,例如:CarCreated(Id)、CarSeatColored(Red)、CarWashed( ) 等(所有这 3 个事件都是由于单个命令而发生的)。外部系统期望接收一个外部事件 CarMaintainenceDone(Id, repainted=true,washed=true, somevalue=22);
现在,如果我有一些复杂的逻辑来制作这个 CarMaintainenceDone 事件(比如 if(color==red then in projection somevalue==22 else 44) - 这应该进入投影代码还是域的一部分?
更新 2
让我试着给你一个新的例子。忽略域的建模方式,因为这只是示例:
如您所见,我们有包含 Multiplier 的 AggregateRoot,它只是用来以正确的名称调用事物。当我们进行乘法运算时,我们首先将整数 1 发送到 ObjectA,它有一些逻辑来设置内部状态并发出 ObjectAHasSetParam 事件。 ObjectB 也是如此。最后,ObjectC 监听所有这些事件,并在 paramsHasBeenSet 上进行实际的乘法运算。
在这种情况下,我会在事件存储中保留事件列表:
[ObjectAHasSetParam , ObjectBHasSetParam , ObjectCHasMultiplied ]
我的意思是:如果我将所有这些事件一个一个地发出进程外 - 其他人更新的状态可能会不一致,因为这 3 个事件只有一起才有意义。这就是为什么我想做一些类似投影的东西,但我认为在这种情况下我只需要一起发布这些事件的列表,而不是一个事件一个事件。
class AggregateRoot{
Multiplier ml;
void handle(MultiplyCommand(1,2)){
ml.multiply(1,2);
}
}
class Multiplier{
ObjectA a;
ObjectB b;
ObjectC res;
void multiply(1,2){
a.setParam(1);
b.setParam(2);
publish(paramsHaveBeenSet());
}
}
class ObjectA{
int p;
void setParam(1){
p = 1 + 11;
publish(ObjectAHasSetParam(12));
}
}
class ObjectB{
int p;
void setParam(2){
p = 2 + 22;
publish(ObjectBHasSetParam(24));
}
}
class ObjectC{
int p1; int p2;
int res;
listen(ObjectAHasSetParam e1){
p1 = e1.par;
}
listen(ObjectBHasSetParam e2){
p2 = e2.par;
}
listen(paramsHaveBeenSet e3){
res = p1 * p2;
publish(ObjectCHasMultiplied(288));
}
}
【问题讨论】:
-
这是一个奇怪的问题;您应该提供有关上下文的更多信息;事件是什么,你正在合并什么,等等。
-
什么是“外部域事件”?!
-
CarMaintainenceDone事件引发后会发生什么?CarAggregate 是否使用此事件来修改其行为以应对其接收到的未来命令? -
没有。这个事件 (CarMaintainenceDone) 被另一个聚合在另一个有界上下文中使用(实际上 saga 接收它并转换为这个另一个聚合的命令)来处理其他一些东西。
-
查看我回答的最后一句话:“在这个特定的上下文中,我将从 Car 聚合生成事件,以简化代码。”
标签: domain-driven-design projection cqrs event-sourcing