是否有一种可接受的方式来处理包含另一个聚合ID的事件?

时间:2016-09-08 14:39:58

标签: domain-driven-design event-sourcing get-event-store

假设为客户生成了发票。这个具体事件看起来像这样:

invoice.raised {
   "id": "4dbcff82-6f35-4155-9aec-f8185c1f932f",
   "total": "50.00",
   "description": "Order 01133",
   "customer_id": "c2206843-414d-454f-9894-57c6b11b9c00"
}

这是一个相当简单的示例,它指的是发票所属的客户汇总。

当我想创建发票视图并且我想在发票中嵌入客户名称时,难以表现出来。我可以做两件事 - 丰富原始事件以包含客户的名称或加载客户视图以找出我在构建我的发票视图时的名称。 现在这不是一个非常复杂的例子,但在某些情况下,再丰富事件变得几乎无法管理,因为我最终将各种聚合的许多属性复制到事件中,这些属性非常特定于其他聚合。

除了丰富事件之外,是否有一种普遍接受的处理方法?因为每次现在都会引发invoice.cancelled事件,我还必须再次包含发票金额,以便我可以使用新余额更新Customers视图。

2 个答案:

答案 0 :(得分:1)

  

当我想创建发票视图并且我想在发票中嵌入客户名称时,难以表现出来。

     

除了丰富事件之外,还有一种普遍接受的处理方法吗?

如果你可以帮助它,你不想走富裕事件的道路 - 这会增加你实施中的耦合,这会使你的模型变得更加昂贵。

UI组合技术可能会指导您朝着有用的方向发展。 Udi Dahan多次写到他们。一些例子

基本情节 - 而不是InvoiceView获取客户状态,并使用该状态生成客户视图,而InvoiceView将责任的一部分委托给客户组件本身

InvoiceView (e : invoice.raised) {
    InvoiceWidget(e.id)
    CustomerWidget(e.customer_id)
}

答案 1 :(得分:1)

  

在某些情况下,再次丰富事件变得几乎无法管理,因为我最终将各种聚合的许多属性复制到事件中,这些属性非常特定于其他聚合。

没错,它会使您的活动难以管理。

所以我说只有customer_id并且在构建阅读模型时询问客户名称

  • 当建立非规范化视图时,它可以处于投射时间。
  • 可以在查询时,基于发票和客户构建结果视图模型(对于此用例,您可以拥有仅customer_idcustomer_name的客户专用列表)
  

因为现在每次提出invoice.cancelled事件,我都必须再次包含发票的amount,以便我可以使用新的余额更新客户视图。

我希望,

invoice.cancelled事件由Invoice聚合根触发,并且它拥有amount因此将amount置于invoice.cancelled事件中是很自然的。

invoice.raised事件也由Invoice聚合根触发,但它不拥有客户名称。无论如何,它无法检查客户名称在特定时间点是否一致。这就是为什么不是嵌入客户名称,而是在构建阅读模型时可以简单地查询它。

BTW关于设计事件有一个很好的阅读 - 6 Code Smells with your CQRS Events – and How to Avoid Them