2

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

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

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

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

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

4

2 回答 2

2

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

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

所以我想说,customer_id当你建立你的阅读模型时,只需询问客户姓名就足够了:

  • 它可以在投影时间,当非规范化视图被构建时。
  • 它可以在查询时,根据发票和客户构建结果视图模型(对于这个用例,您可以有专用的客户列表,customer_id并且customer_name只有)

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

invoice.cancelled事件是由发票聚合根触发的,我希望它拥有amount,所以很自然地放入amount事件invoice.cancelled中。

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

顺便说一句,有一本关于设计事件的好读物——CQRS 事件的 6 种代码味道——以及如何避免它们

于 2016-09-08T17:15:20.923 回答
1

当我想创建发票视图并且想在发票中嵌入客户的姓名时,困难就显现出来了。

除了丰富事件之外,是否有一种普遍接受的方式来处理这个问题?

如果您可以提供帮助,您不想走丰富事件的道路——这会增加实现中的耦合,从而使更改模型的成本更高。

UI 组合技术可能会引导您朝着有用的方向发展。乌迪·达汉(Udi Dahan)多次写过关于他们的文章。一些例子

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

InvoiceView (e : invoice.raised) {
    InvoiceWidget(e.id)
    CustomerWidget(e.customer_id)
}
于 2016-09-08T17:02:28.513 回答