首页 > 解决方案 > DDD:如何防止购买在没有相关撤回的情况下被持久化

问题描述

假设员工可以使用其雇主提供的某种“福利积分”购买产品。

我有一个CreditsAccount持有信用额度和对员工的引用Purchase的实体,我想将其建模为持有对 CreditsAccount 的引用并且产品正在购买的实体。

如果我有一个PurchaseRepository.save()方法,我怎样才能防止 aPurchase被保存而不做任何撤消CreditsAccount

解决方案 1

Purchase 是聚合 CreditsAccount 的子实体,我没有任何 PurchaseRepository 而是帐户上的一个方法,就像CreditsAccount.AddPurchase(purchase)在内部进行提款一样。当我使用 a 持久化 CreditsAccount 时,CreditsAccountRepository.save(account)我还将购买保留在正确的表中。

但这意味着每次我加载 CreditsAccount 进行新购买时,我还必须加载该帐户上的购买列表,对吗?

解决方案 2

我构建了一个新PurchaseTransaction实体,它包含对 CreditsAccount 和 Product 的引用,并提供类似PurchaseTransaction.commit(). 在提交时,它实际上根据产品价格从参考账户中提款,其内部状态从 切换uncommittedcommitted。然后我有一个 PurchaseTransactionRepo.save(purchaseTransaction) :

在这种情况下,PurchaseTransactionRepo 仅提供一种在 db 上写入的方法,因为实际上 PurchaseTransaction 并不真正属于任何表,而 PurchaseRepository 是只读的并且仅提供获取“已提交”购买的方法。

我不喜欢这个解决方案是有一个 Repo,它实际上对 PurchaseTransaction 的状态(已提交或未提交)进行了一种验证逻辑,而且 Uncommitted PurchaseTransaction 并没有真正持久化似乎具有误导性。

您能否向我推荐其他符合 DDD 概念的解决方案?

一些上下文:不是一个真正的应用程序,而是一个 kata 练习,我必须在其中将一个贫血域重构为一个丰富的域。在贫血症中,有一项服务可以在一次交易中提取帐户并保存购买。然后我可以通过 api 调用获得购买清单。我想用丰富的实体对其进行建模并“强制”无效状态不是“可持久的”

标签: repositorydomain-driven-designentities

解决方案


Purchase似乎是一个很好的 saga 候选者,它可以被认为是一个代表一个过程的实体。在没有更多上下文的情况下,我将其建模为类似于现实世界中通常处理付款的方式(为非常 CQRS/演员模式拟人化表示歉意)并且在四种状态下购买:打开、完成、资助、过期和完成.

  • 一旦购买实体知道要购买的物品及其成本,它就可以最终确定,这使其进入最终状态并防止将来更新物品和成本。它以这种状态保存。

  • 然后,它会尝试从员工的账户中保留信用额度,并在最后期限内完成提款或取消保留。如果成功,它会进入“已资助”状态并保存。

我可能会对已资助并影响实际提款的购买进行一些其他流程扫描(因为我们不是这里的事件采购),这允许购买由履行组件提取,以及将购买保存在状态“已完成”(如果购买过期,有很多选择。


推荐阅读