domain-driven-design - 事件源系统中的预测

标签 domain-driven-design projection cqrs event-sourcing

在事件源系统中,我有一个类型为 Order 的聚合根。我们假设正在发生以下事件:

  • OrderPlaced(orderId、placedAt、customerId、orderLines),其中 OrderLine(lineId、productId、价格)
  • 订单已接受(orderId)

假设我们需要两个不同的投影:

  1. 包含每个客户按年份分组的所有已接受订单的总价格的预测。像这样的事情:

     OrdersByCustomer(customerId, summationOnAcceptedOrdersByYear) where SummationOnAcceptedOrdersByYear(year, sum)
    

    此处的问题是 OrderAccepted 不包含 customerId。因此,当投影收到 OrderAccepted 时,它无法获取当前投影状态,因为 customerIddocumentId。值得注意的是,我将投影存储在 Scylla 中 - 只能通过分区键查询 - 并且投影状态只是一个 json 表示形式。因此,除了 documentId/projectionId 之外,无法通过任何其他内容查询。也许这不是投影技术的理想选择......?

我想如果继续使用 Scylla,我有两个选择:

  • 要么用 customerId 污染 OrderAccepted。但我认为这不是一个好方法 - 然后我需要将其合并到与投影相关的所有事件中,其中projectionId/documentId与aggregateId不同。

  • 或者有一个单独的表,其中包含 orderIdcustomerId 之间的映射,因此投影可以查询 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/

    相关文章:

    architecture - 将DDD应用于Northwind数据库

    java - Hibernate 忽略带有投影 beans 的链式 setter

    architecture - 如何在 DDD/CQRS/EventSourced 项目中建模投票/点赞系统?

    PHP领域模型

    domain-driven-design - 将业务逻辑放在 DDD 的何处

    localization - 本地化来自域对象(实体)的验证消息

    azure - 如何使用服务器端的列投影将 Parquet 文件从 Azure Blob 读取到 Pandas DataFrame 中?

    cqrs - 如何在 EventStore 3.0 中使用 GetStreamsToSnapshot 创建快照

    asp.net-mvc - ICommandHandler/IQueryHandler与异步/等待