如何在多个有界上下文中创建对象?

问题描述 投票:0回答:1

假设我有产品型号。我有目录上下文、仓库上下文、运输上下文、销售上下文。我的产品实体分散在这些上下文中。目录、仓库、销售和运输都有自己的产品。 Id 属性是共享的。 Sales 有界上下文关心价格、产品名称、描述。仓库有界上下文关心大小、位置、数量、质量等等。

现在我希望销售人员向系统添加新产品。销售人员从 UI 输入产品的所有必要详细信息,包括名称、描述、数量、价格等,然后单击提交。因此,我的系统应该使用这些请求详细信息为每个上下文创建产品对象。销售部门将创建自己的产品,仓库将创建自己的产品,依此类推。

一旦我的控制器收到请求,我将使用请求详细信息创建 CommandObject。 (在每个上下文中创建产品的命令)。

控制器

Guid id = Guid.NewGuid();

var salelsCreateProductComand = new salesContext.application.product.CreateproductCommand(id, …);
var warehouseCreateProductComand = new warehouseContext.application.product.CreateproductCommand(id, …);
var shippingCreateProductComand = new shippingContext.application.product.CreateproductCommand(id, …);

var salesContextTask = _sender.Publish(salelsCreateProductComand);
var warehouseContextTask = _sender.Publish(warehouseCreateProductComand); 
var shippingContextTask = _sender.Publish(shippingCreateProductComand);

await Task.WhenAll(salesContextTask, warehouseContextTask, shippingContextTask);

我将从控制器生成 Guid 并将其设置为产品 id。(然后每个上下文将共享相同的 id)然后将命令发布到 MediatR。然后每个上下文都会接受命令,相关的处理程序将处理它。

但是一个上下文可能由于某种原因无法创建其产品对象。可能是数据库故障或验证失败。所以我们还需要从其他模型回滚项目对象。

遇到这种情况我们该如何处理?

如果您能解释我的解决方案中的任何建议/改进/错误/不良做法,我将不胜感激。

PS:

我对从控制器生成产品 id 感觉很糟糕。

domain-driven-design cqrs clean-architecture bounded-contexts modular-monolith
1个回答
0
投票

这个问题需要SAGA模式。在这种情况下,您有多种最佳实践:

  • 要理解 SAGA 是什么,最好异步思考。每个有界上下文都必须处理 ProductCreatedEvent。他们每个人都会尝试将产品保存在他们的数据库中,并发出一条成功或失败的消息,以向其他有界上下文发出结果的信号。其他有界上下文可以决定如何处理收到的消息。

  • 有两种类型的 SAGA 可以在有界上下文之间设计此类消息传递和通信:基于编排基于编排

  • 在基于编排的 SAGA 中,没有中央模块来编排有界上下文之间的通信。他们通过消息代理以发布-订阅风格进行通信。您可以按顺序设计事件(事件在处理时一个接一个地发出,它们按顺序耦合,并且每个限界上下文都知道下一步事件),也可以将它们设计为不考虑其他限界上下文(设计简单,但会出现复杂的问题,例如无序消息)。

  • 在基于编排的 SAGA 中,中央模块编排在多个有界上下文之间处理请求的步骤。该模块保留一个状态管理器对象(如工作流对象)来跟踪每个有界上下文的状态。

  • 仅使用SAGA模式并不能解决一致性问题(因为可能会出现消息传递失败)。最好将其与发件箱模式一起使用(这确保当实体成功提交到数据库时最终会发送消息)。

© www.soinside.com 2019 - 2024. All rights reserved.