Domain driven design DDD:选择聚合根

Domain driven design DDD:选择聚合根,domain-driven-design,aggregate,Domain Driven Design,Aggregate,在我的例子中,我有两个主要概念:用户(系统的主要公民)和组。 组有两个子集合:等级和角色。没有团队,等级和角色就没有意义。 当用户被分配到组时,我们还必须选择1个角色和1个等级,并将它们分配给用户和组之间的关系 问题: 我这里有多少聚合根?从用户方面看,它显然是一个用户(系统的主要概念),但它与组的关系如何?DDD规则禁止AFAIK引用聚合根以外的实体 DDD规则禁止AFAIK引用聚合根以外的实体 嗯,我不会说这是“DDD规则所禁止的”。。。有时你别无选择。我必须考虑与根的集合相关联的“实体集

在我的例子中,我有两个主要概念:用户(系统的主要公民)和组。 组有两个子集合:等级和角色。没有团队,等级和角色就没有意义。 当用户被分配到组时,我们还必须选择1个角色和1个等级,并将它们分配给用户和组之间的关系

问题:

我这里有多少聚合根?从用户方面看,它显然是一个用户(系统的主要概念),但它与组的关系如何?DDD规则禁止AFAIK引用聚合根以外的实体

DDD规则禁止AFAIK引用聚合根以外的实体

嗯,我不会说这是“DDD规则所禁止的”。。。有时你别无选择。我必须考虑与根的集合相关联的“实体集合”的大小。有时,您可以在同一聚合中维护关联,并使用某种“延迟负载”来避免资源消耗。弗农的iDDD书[1]围绕这个具体案例提供了一些建议和用例。看看他的博文[2]

[1]
[2]

根据您在一致性方面的业务需求,您至少有以下选项:

  • 您有5个聚合根:用户、组、级别、角色和用户分配。最后一个必须保护不变量“我们还必须选择1个角色和1个等级”。对于生命周期管理,您使用AR之间的最终一致性。例如,删除组时,还必须删除孤立列组、角色和用户分配

  • 您有用户(UserAssignment作为嵌套实体)和组(Role和Rank作为嵌套实体)。ARs内部具有很强的一致性(当您删除一个用户时,其所有附件也将被删除),并且最终用户和组之间具有一致性

  • 你应该用什么?只有你能决定。例如,如果选择第一个选项并删除用户,则在删除其分配之前可能会有秒/分钟/小时的延迟

    强Consystence应该只用于保护真正的业务不变量,因为它不便宜


    另外,如果您需要保留对另一AR中嵌套实体的引用,那么您应该重新考虑聚合根边界,因为您的设计很可能是错误的。

    我将更改一些单词,看看它是否有帮助(假设):

    我有
    订单
    产品
    。当我将
    产品
    添加到
    订单
    时,我必须选择
    存储
    颜色

    您将如何对此进行建模

    color
    很可能是一个值对象,但
    Store
    不是。我会选择一个
    OrderItem
    Value对象,它包含一个
    color
    Value对象和一个
    StoreId
    值来捕获关系。
    Order
    将包含一个
    OrderItem
    条目列表

    删除
    color
    条目很好,因为我们已经将该位反规范化到
    OrderItem
    中。我们可以使用另一个值对象来表示
    存储
    ,但通常我们不会删除存储,也不会进行处理来处理删除,或者更典型的是,使用引用完整性约束来防止删除已使用的
    存储

    如果您考虑删除<代码>订单< /代码>,则只删除<代码> OrthuttIs>代码>关联。


    在您的例子中,
    User
    Group
    可能是聚合根,我将添加一个
    UserGroup
    (或者康斯坦丁使用的
    UserAssignment
    )。
    UserGroup
    包含关联和相关位。但是,您必须确定真正的域结构。

    或者您可以使用最终一致性。基本上,没有父组,角色和级别都没有意义。它就像:“你好,我是国王[角色]。”什么[群体]的国王。“NullPointerException的”。应用程序本身非常以用户为中心,一切都围绕着用户的概念发展。在第二个选项中,碰巧我们有两个聚合-用户和组,对吗?但是用户分配(用户实体中的嵌套实体)引用组聚合中的嵌套实体。这是你的意思还是我不明白你的意思?然后使用选项1和2的组合。我还试图让您了解在设计聚合时如何思考:一致性边界。没有绝对的答案。我们可以根据您的需要进行讨论,以便理解,但没有人可以确切地告诉您当前的解决方案:实现5个聚合根:用户、组、排名、角色和用户分配。角色和等级与其父组有关系,因为用户通常希望按照特定顺序遵循该关系(foobar[group]的国王[Role]),而且该应用程序的阅读量很大。接下来,我们只创建一个GroupService并将所有不变量推送到那里(例如:组中只能有一个king-createRoleForGroup(组,角色)->loadKingRoleForGroup(组ID)->found nothing->save(角色))。这种方法还允许我为角色制定自定义规范(如get all kings),从而优化查询。我将写操作(它们遍历组,从而保护不变量)和读操作(只需要信息)分开。如果我想删除一个组-我首先检查活动的用户分配,如果它们存在-暂停执行(用户是事件源,我们必须先取消分配用户)。如果不是-删除其子聚合及其本身。这种方法有效吗?