首页 > 解决方案 > 具有多对多关系的 DDD 聚合设计示例

问题描述

我想通过一个建模练习来尝试更好地理解 DDD,特别是在存在多对多关系的情况下

让我们以 Xbox 用户及其成就为例。

如果您不熟悉,这是背景:Xbox 上的每个游戏都有成就。用户将拥有他们拥有/玩过的游戏列表,他们可以解锁这些游戏的成就。

这里是多对多的关系,一个用户可以有很多游戏,一个游戏可以有很多用户。

不用多说,这里肯定有两个聚合根。用户和游戏。游戏聚合根有一个成就列表。

我的困惑来自于跟踪特定游戏的用户进度。例如他们有哪些游戏,以及他们在每场游戏中取得的成就。

在典型的 CRUD 设计中,它可能看起来像这样: 在此处输入图像描述

您现在将如何建模这是 DDD?

用户游戏和用户成就将包含有关每个进度的信息。

这是我目前认为的解决方案,但是对吗?

在此处输入图像描述 用户和游戏都是聚合根。

一个游戏的进度和它的个人成就似乎也有联系,我会说这是它自己的总根。这是因为就像游戏及其成就一样,它可能具有交易边界。当您在游戏成就上取得进展时,这可能会影响游戏的进度(例如,解锁成就会增加游戏玩家获得的总得分。)

我一直听说你要解决多对多关系,这通常没问题,但在这里,关系有自己的数据,我认为这种关系也不属于。

您可能会争辩说您会将它放在用户聚合上,但我担心它会增加该用户聚合的权重,并且没有理由让它存在。我不认为有任何事务边界,我不喜欢当你想加载它时必须加载所有用户的游戏。即使这是延迟加载,我担心它可能会导致并发问题?

这就是为什么我认为这里的多对多关系是有效的,以及为什么新的聚合根可能是合适的。

也是名称用户游戏进度甚至正确。知道域,你有什么建议?

谢谢,任何帮助都会得到广泛的应用。

标签: many-to-manyaggregatedomain-driven-design

解决方案


您在这里寻找的是领域事件。从微软文档:

使用域事件显式地实现域内更改的副​​作用。换句话说,使用 DDD 术语,使用领域事件显式地实现跨多个聚合的副作用。或者,为了获得更好的可伸缩性并减少对数据库锁的影响,请在同一域内的聚合之间使用最终一致性。

“游戏的进展”对我来说似乎不是一个总根。要更新“游戏进度”,您可以从聚合中引发域事件,例如“User_Moved”,并从User聚合中引发类似事件Game。然后,您可以订阅这些事件以更新游戏进度。此外,由于域事件是在内存中的,因此您可以在单个事务中实现这一点。


推荐阅读