在事件源系统中,我有一个类型为 Order 的聚合根。我们假设正在发生以下事件:
- OrderPlaced(orderId、placedAt、customerId、orderLines),其中 OrderLine(lineId、productId、价格)
- 订单已接受(orderId)
假设我们需要两个不同的投影:
包含每个客户按年份分组的所有已接受订单的总价格的预测。像这样的事情:
OrdersByCustomer(customerId, summationOnAcceptedOrdersByYear) where SummationOnAcceptedOrdersByYear(year, sum)
此处的问题是
OrderAccepted
不包含customerId
。因此,当投影收到OrderAccepted
时,它无法获取当前投影状态,因为customerId
是documentId
。值得注意的是,我将投影存储在 Scylla 中 - 只能通过分区键查询 - 并且投影状态只是一个 json 表示形式。因此,除了 documentId/projectionId 之外,无法通过任何其他内容查询。也许这不是投影技术的理想选择......?
我想如果继续使用 Scylla,我有两个选择:
要么用
customerId
污染OrderAccepted
。但我认为这不是一个好方法 - 然后我需要将其合并到与投影相关的所有事件中,其中projectionId/documentId与aggregateId不同。或者有一个单独的表,其中包含
orderId
和customerId
之间的映射,因此投影可以查询customerId
- 这表可能需要在订单聚合的命令处理程序中更新。或者,我们可以对
CustomerIdByOrderId
进行投影 - 但在这里,我认为投影可以位于事件流的不同位置 - 这也可能会导致问题。
对每种产品的所有已接受订单的价格进行汇总的预测。像这样的事情
SummationForProducts (productId, orderSummation)
所以这里我们有一个依赖于 OrderPlaced 和 OrderAccepted 的投影。问题是,由于 OrderPlaced 可能包含多个 orderLine,从而跨越多个投影 - 我们需要在接收 OrderPlaced 时更新多个投影。这在事件溯源预测中是否正常 - 更新事件的多个预测?
这里出现了同样的问题,因为 OrderAccepted 不包含 OrderPlaced 事件中的 ProductIds。因此,在这里我们可能可以使用类似的方法来创建一个包含 orderId 和 ProductIds 之间的映射的表
我想知道更有经验的事件源如何解决这些问题......? :) 对此的任何意见都将受到高度赞赏。
最佳答案
事件源系统的优点在于,您需要的所有信息都(或者至少应该)封装在事件中。
我假设您正在使用 CQRS 模式,并且根据您的描述,问题集中在投影应该是什么样子。换句话说,您实际上不需要更改命令/事件方面的任何内容,而是专注于如何从事件中获取所需的数据来构建适当的预测。
我不熟悉 Scylla,但您可以自由地以适合您的方式建立您的投影。请记住,投影只是您可以从事件中查询的数据。
我能想到的最简单的事情就是存储每个订单,包括状态。像这样的东西(用可怕的伪代码):
-- Order Summary event handler
on(orderPlaced):
insert into Order(orderId, datePlaced, customerId, orderLines, status)
values (orderPlaced.orderId, orderPlaced.date, orderPlaced.customerId, orderLines, 'placed')
on(orderAccepted):
update Order
set status = 'accepted'
where orderId = orderAccepted.orderId
-- Sum of accepted orders per customer and year
select customerId, year, sum(orderLines.price) from Orders
where status = 'accepted'
group by customerId, year(datePlaced)
-- Sum per product of accepted orders
select productId, sum(orderLines.price) from Orders
where status = 'accepted'
group by orderLines.productId, year(datePlaced)
请注意,上述代码假设事件按顺序处理。
we would need to update multiple projections when receiving OrderPlaced. Is this normal in Event Sourcing Projections - to update multiple projections pr event?
当然,这是完全正常的。您可以使用单个事件来更新多个投影,也可以使用多个事件来更新单个投影,或者两者的组合。
关于domain-driven-design - 事件源系统中的预测,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/66034905/