事件采购 - 显示旧数据

时间:2018-01-05 19:19:51

标签: database cqrs event-sourcing

这是一个菜鸟(我认为)事件采购 问题

作为一个例子,我们有:

  • 鞋匠Bob
  • 顾客Alice

鞋匠鲍勃:

  • " shoemaker_business_locations" (营业地点地址)
    • 第一个地址是" 88d8 - 5 Baker Street" (已添加一月
    • 第二个地址是" 73c6 - 6 Cadman Plaza" (已添加三月
    • 在某些时候(十月)鞋匠从哪里移动  " 5 Baker street"到" 11 Baker street" (几个房子下面的街区)

假设我们有一个" shoe_repair_order" (聚合根?)

  • 我们发生了爱丽丝的修鞋订单 有时候七月之前鞋匠鲍勃搬家 他的营业地点在街区。

  • 让我们说爱丽丝正在查看12月份的订单。 显然,她不必知道鲍勃的业务。 当她看到她的订单时,我认为她应该看到(至少)旧的 营业地点和/或 "订购于5 Baker Street(新地址为11 Baker street - 10月6日更新)"。

问题:我们如何设计Event-Sourced系统以显示订单的旧地址?

  • 我们是否必须始终为我们的订单存储活动,例如 " OrderLocationAdded" 并在我们的订单活动中存储实际地址的副本 - 这样每个订单都会有一个正确的旧位置,只需从事件中获取。 只有发布新的事件,例如" OrderLocationUpdated"然后我们可以更新它 对于那个特定的订单,如果需要的话。

OR

  • 我们是否发出" OrderLocationAdded"活动,并提及地址 " 88d8 AT VERSION 1 ",以便我们知道查找我们营业地点的第1版。 我们将不得不重播" shoemaker_business_locations" 直到我们看到"版本X"我们的地址(在我们的案例中为版本1)。 这就是我们必须对所有版本为的旧订单所做的事情 地址低于当前设置的版本(版本1)。

  • 其他一些方式?

    也许我们的读模型只是存储不同版本的所有地址信息,当我们查询某个版本时 我们不必在我们的写模型中重放事件,而只是从我们的读模型中获取版本1的地址?

4 个答案:

答案 0 :(得分:1)

我认为实现这一目标的最佳方式最终取决于您设计域模型的方式,但这就是我如何解决问题:

我们需要在域模型中表示地址。这意味着,地址将是值对象,实体或聚合。在这三者中,一个地址实际上只能是一个价值对象或该域中的一个实体,因为我们是修鞋应用而不是地址簿。实体具有某些属性,例如通过其ID来区分,以及某些限制,例如仅作为一个聚合的一部分,地址似乎不会满足。因此,我会在这个域中看到一个Address是一个Value Object。

在" shoe_repair_order"上定义OrderLocationAdded事件时聚合,您需要决定是否在事件中包含地址的完整详细信息,或使用对地址的引用。由于Address是一个Value Object(它由数据而不是ID定义),答案是在事件中包含Value Object。这样,当您重放事件以构建订单的当前状态时,它仍将具有原始地址的详细信息。

如果您还要在订单上显示新地址,您可以使用其他事件(例如BusinessMovedToNewLocation)和新地址的详细信息,并将其添加到订单中。此事件不会替换原始地址,它只会允许您显示业务现在位于其他位置的信息性消息。

答案 1 :(得分:1)

您的问题的答案当然取决于您如何定义您的域模型(特别是如何定义您的聚合)。我将解决此问题的方法是有两个聚合:

  • ShoeMaker Aggregate(在您的情况下,存储所有信息,如鞋匠业务的名称,有关此业务的信息'所有者,此鞋匠的所有地址列表,其中每个地址可以包含电子邮件等信息,电话号码,以及一个名为current的bool字段,当前地址可以为true。我想这个AR会有一个名为 - " ChangeShoeMakerCurrentAddress"这会引发一个名为" ShoeMakerAddressesChanged"

  • 订单汇总(包含客户名称,价格,详细信息,订单日期,交货日期等订单的所有信息。)

我们假设我们有一个名为" ShoeMakerOrderReadModel"它可以订阅由ShoeMaker Aggregate和Order Aggregate引发的事件。此读取模型侦听事件并将它们非规范化为POJO / POCO对象。这个POCO / POJO模型可以有一个鞋匠地址列表(其中每个地址都可以包含电子邮件,电话号码和一个名为current的bool字段等信息,对于当前地址可以是真实的。)此AR绝对可以订阅&#34 ; ShoeMakerAddressesChanged"来自ShoeMaker Aggregate的事件,然后更新鞋匠地址列表。

我希望这有帮助!

答案 2 :(得分:0)

由于CQRS,答案很简单:你不能在BusinessMovedToANewLocationEvent中听取 OrderDetailsReadModel。当Business address发生时,您只需在Order details Read model中的当前 OrderPlacedEvent查找和存储。

通过这种方式,您不必在活动中加入任何Address value objectRead model完成所有工作。

如果您因其他原因需要,您可以收听此活动,但只是不要更新地址。例如,Read model可能更智能,另外还有一个addressChangedInTheMeanTime boolean标记,以告诉Alice看到的Address 是旧的,但因此取决于您的业务需求。

答案 3 :(得分:0)

以下是一些选项:

  1. 在您的鞋匠阅读模型中,包括地址列表,包括他们变为活动的日期。这样,当您在订单投影中处理订单事件时,您查询鞋匠读取模型并获取订单日期正确的地址(即使您稍后重建投影,这也将起作用)。这样做的缺点是两个视图之间的耦合(订单投影现在取决于鞋匠的查询API,所以你需要确保鞋匠投影是最新的和可用的)
  2. 如果您有订阅多个事件流的方式,以便您接收大致全球订单的事件,则在您的订单投影中还会处理鞋匠地址事件(创建和更新)。将鞋匠的迷你桌子保存到“当前”地址(意味着您处理的事件中的当前地址,允许重放正常工作)。然后在处理订单创建事件时,只需查找表中的当前地址并将其复制到订单视图中。这是一个更多的代码,但避免了视图之间的依赖关系,并避免在shoemaker视图中需要地址历史记录(尽管由于其他原因你可能还需要它)。
  3. 让鞋匠地址成为订单域模型的一部分。它将需要包含在订单创建命令中(可能通过控制器层中的命令丰富,在鞋匠读取视图中查找)。这似乎没有必要,因为订单没有商店地址的概念,这个概念与商店的概念是分开的(这与交货地址不同,交货地址通常是某种方式的按订单商品)。 / LI>