DDD 和 CQRS:从单个命令处理程序使用多个存储库?

CKK*_*CKK 4 domain-driven-design cqrs

简单电子商店的典型示例。

假设用户将一些商品添加到购物篮并单击“结帐”。发出“创建订单”命令。现在,在实际创建状态为“预计付款”的订单记录以及数据库中相应的订单行之前,我们必须检查用户选择的商品是否仍然可用(也许某些商品在用户将其添加到购物篮时可用)但不再是了)。我们还必须保留它们,这样它们就不会在用户仍在结帐时突然消失。

所以我的问题是如何执行这个“检查和保留”例程?在我看来,我有多种选择:

  • 在“创建订单”命令处理程序中,用于ProductStockRepository保留产品,然后在成功后用于OrderRepository创建订单。这意味着,我们在单个处理程序中使用多个存储库。
  • 不要ProductStockRepository直接在“创建订单”处理程序中使用,而是创建一个ProductStockService并在其上调用方法来检查和预订产品。我们仍然在单个处理程序中使用多个存储库,但库存存储库的使用是抽象的。
  • 创建内部“储备产品”命令并从“创建订单”命令处理程序内部调度并等待它。
  • “结账”按钮发送“预订产品”命令,而不是“创建订单”。在“保留产品”处理程序中,我们尝试保留产品,并在成功时调用“保留产品”域事件。相应的事件处理程序被触发,我们在其中创建一个订单。
  • 还有其他方法吗?

这不是关于如何最好地建模电子商店结账流程的问题。以上只是一个例子。我想在许多不同的应用程序中可能会有许多类似的场景。

Fra*_*lls 5

您提出的问题的解决方案不是编码“风格”或遵循良好的 DDD 实践的问题。如果在单个处理程序中使用多个存储库解决了您的问题,我相信您应该认为它是一个不错的选择。

但这种场景的主要问题是,在许多系统中,订单和库存位于不同的服务/限界上下文中,因此位于不同的数据库中。库存甚至可能位于不受您控制的外部系统中。这意味着您无法通过交易方式预订股票并下订单,因此您可能会面临预订股票而不下订单的风险,反之亦然。

建议使用事件来处理这些场景的原因是,使用事件可以可靠地开发此类工作流,尽管这会带来新的复杂性。通过一些技术,可以可靠地保留库存并发布一个事件,而在另一方,可靠地捕获付款并发布另一个事件,然后下订单并发布另一个事件等。此工作流程可能涉及以下内容发件箱模式、重试、传奇、补偿操作(在某一步骤失败时回滚之前的步骤)等。