【发布时间】:2016-03-08 05:11:00
【问题描述】:
基本上,问题是:
如何正确构建事件源系统的事件存储,应该能够:
将一个聚合转换为另一个,
保持相同的ID,
并且仍然能够从事件流中重构它?
现在是我的例子:
我有一个ProspectiveCustomer,可以像这样转换为PayingCustomer:
ProspectiveCustomer::convertToPayingCustomer(ProspectiveCustomerId $id)
PayingCustomer 将保持相同的 Id,以便跟踪其生命周期。
所以现在想象一下以下事件流:
- ProspectiveCustomer 已添加到 CRM 中
- 向潜在客户提出了要约
- ProspectiveCustomer 接受了报价,因此转换为 PayingCustomer
- PayingCustomer 支付了账单
让我们专注于第 4 点):
我们将有一个 commandHandler 接收一个 paymentCommand {customerId:"123", amount:"500€"}。 它的工作是:
- 根据事件历史重构 PayingCustomer
- 致电 PayingCustomer::pay(Money $amount)
我的问题是关于 1) 从历史中重构:
EventStorage 服务将:
- 查找 AggregateId
- 加载事件(SELECT * FROM Events WHERE ID = 'xxx')
事件堆栈现在将包含:
- 已添加潜在客户
- ProspectiveCustomerWasMadeAnOffer
- ProspectiveCustomerAcceptedTheOffer
commandHandler 如何处理PayingCustomer::reconstituteFromHistory(EventsHistory $events) 而$events 是从ProspectiveCustomer 发出/可应用于ProspectiveCustomer 的事件
编辑
目前我正在处理 PayingCustomer 拥有自己的 Id,但持有对 ProspectiveCustomerId 的引用的问题。
但考虑到:
- 这是相同的有界上下文,
- 非常同一客户的生命周期(ProspectiveCustomer 在 PayingCustomer 开始时结束),
感觉有点乱,因为模型现在被 2 个 Id 污染了,而一个应该就足够了。
如果不是事件源系统,我肯定会选择一个唯一的 ID。
话虽如此,考虑到事件溯源只是一个实现细节,我正在寻找一种方法让两个聚合保持相同的 ID。
【问题讨论】:
-
当然你会有一个
ProspectiveCustomerConvertedToPayingCustomer事件。并且将其应用于 PropsectiveCustomer 并返回 PayingCustomer 是没有问题的 -
但问题是事件流转换后的重构
-
我认为“付费客户”和“潜在客户”是“状态”而不是实体。这就是我误解的地方。很抱歉造成混乱。
-
感谢您的关注。潜在客户可能具有与付费客户完全不同的不变量,因此需要将大客户聚合分解为 2 个更小但更精确的 AR
-
你不转换,你创建一个新的聚合。当您创建一个聚合时,无论如何您都会使用一个外部 id,它是在事件中提供给您的。您复制您需要在付费客户汇总中拥有的所有潜在客户汇总详细信息。用两个词——没有聚合转化,只是正常的业务流程。
标签: php cqrs event-sourcing aggregateroot