DDD - 如何设计不同有界上下文之间的关联

时间:2013-09-12 09:52:19

标签: domain-driven-design aggregateroot bounded-contexts

我已经设置了一个正在使用ORM填充的域项目。域包含不同的聚合,每个聚合都有自己的根对象。 我的问题是如何处理跨越聚合边界的属性?

  • 这些属性是否应该忽略边界,以便有界上下文A中的域对象具有对上下文B中对象的引用?
  • 或者,如果没有从上下文A到B的直接链接,并且上下文A中的对象是否具有“int ContextBId”属性,该属性可用于通过B聚合根从B获取域对象?
  • 或......

一个例子:
上下文A =用户
背景B =游戏

Users上下文中有一个对象UserOwnedGames。此对象具有属性User,该属性是对同一Users上下文中的对象的引用。该对象还具有Game的属性,该属性显然不在用户中,而是在Games上下文中。

这种关系会怎样(或应该?)?在数据库中很清楚(即2个外键),但代码应该是什么样的?

3 个答案:

答案 0 :(得分:15)

听起来您的User上下文也需要一个Game实体。但请注意,这不一定是Game上下文的根Game实体。这两个有界的上下文可能对Game是什么以及它具有什么属性有不同的看法。只有身份将两个游戏对象联系在一起。

User Context
{
    Aggregate Root User
    {
        Identity;
        Name;
        OwnedGames : List of Game value entities
    }

    Value Entity Game
    {
        Identity;
        Name;
    }
}

Game Context
{
    Aggregate Root Game
    {
        Identity;
        Name;
        Owner : User value entity
        HighScore : int
        TimesPlayed : int
        ... A whole bunch of other properties which are not relevant in the User context
    }

    Value Entity User
    {
        Identity;
        Name;
        // No OwnedGames property, in this context we don't care about what other games the user owns.
    }
}

答案 1 :(得分:3)

您应该避免跨BC的数据库引用 - 您不应该尝试确保来自不同BC(事务)的聚合之间的引用完整性。理想情况下,交易应该只存在于单个聚合内部,甚至不是BC。

更好地使用ID的简单值对象 - UserId和GameId - 并在需要时将它们分配给实体。这样,这些“远程”实体完全分离,因此您不必担心它们的连接。可以使用消息传递平台实现同步。

如果你有空闲时间阅读这些有价值的文章(由Vaughn Vernon撰写):

答案 2 :(得分:1)

这取决于您使用的有限上下文策略。

如果您选择共享内核,我认为在它们之间建立直接关系(直接引用或标识符引用,我相信其他人将在其他答案中解释其优缺点)。并且您还提到了由数据库表集成的这些对象。

但是如果选择反腐败层,你最好将它们分开(只使用标识符来保持关系),使用适配器转换器进行集成(并且没有数据库集成)。