【问题标题】:Searching for a Child across Aggregate Roots跨聚合根寻找孩子
【发布时间】:2013-11-25 10:12:00
【问题描述】:

存储库模式建议您只能提取聚合根。但是,如果您不知道它是父(根),您将如何仅使用它的唯一身份(Child.ID)来检索一个孩子?

class Parent
{
    public int ID { get; set; }
    IEnumerable<Child> Children { get; private set; }
}

class Child
{
    public int ID { get; private set; }
    public virtual Parent Parent { get; private set; } // Navigational model
}

我的应用程序是无状态的(web),为简单起见,请求只包含孩子的 ID。

我正在考虑三种方法:

  1. 打电话给所有的父母,然后礼貌地问他们谁拥有这个孩子。
  2. 在 ParentRepository 中有一个名为 getGetChildByID 的特殊例程,这有点使存储库的抽象失败。
  3. 修改请求以包含父级,但似乎没有必要,因为您已经拥有唯一身份。

【问题讨论】:

  • ChildRepository 类中创建GetChildByID(..) 方法?
  • 如果您可以在没有父母的情况下识别他们,那么孩子应该是一个聚合体。
  • @Hippoom 我对Aggregate Root的了解是有限的,你是说一个实体只要有唯一的身份就可以被认为是一个根?我已经更新了代码示例。
  • 如果领域专家想要单独跟踪实体,则该实体应该是一个聚合。例如,假设领域专家不会在没有 Order 的情况下跟踪订单行,那么 Order 是一个聚合但 orderLine 只是一个本地实体。即使在技术上,我们也给 orderLine 一个唯一的 id。
  • @Hippoom +1 我想你已经一针见血了。这个孩子可能是一个有界上下文中的聚合根和另一个上下文中的值对象。

标签: c# domain-driven-design repository-pattern ddd-repositories aggregateroot


【解决方案1】:

您似乎实际上在这里查看的是不同的有界上下文。您在问题中提到 “存储库 ... 只能拉聚合根。”;这是对的。另一个答案还提到,如果需要查询子对象,子对象也可能是聚合根。这也可能是正确的在不同的有界上下文中。一个实体很可能在一个上下文中是聚合根,而在另一个上下文中是值实体。

Users 的域和他们在设备上安装的手机/平板电脑Apps 为例。在用户的上下文中,我们可能需要用户的基本属性,例如姓名、年龄等,并且我们可能还需要用户在其设备上安装的应用程序列表。在这种情况下,User 是聚合根,App 是一个值对象。

bounded context UserApps
{
    aggregate root User
    {
        Id : Guid
        Name : string
        Age : int
        InstalledApps : App list
    }

    value object App
    {
        Id : Guid
        Name : string
        Publisher : string
        Category : enum
    }
}

在另一种情况下,我们可能会以App 为中心的世界观,并确定App 是聚合根。例如,我们想报告哪些用户安装了给定的应用程序。

bounded context AppUsers
{
    aggregate root App
    {
        Id : Guid
        Name : string
        InstalledBy : User list
    }

    value object User
    {
        Id : Guid
        Name : string
        InstalledOn : Date
    }
}

这两个有界上下文都有自己的存储库,该存储库返回各自的聚合根。您对数据的看法存在细微但至关重要的差异。

我认为,如果您退后一步思考为什么要查询子对象,您可能会发现您实际上处于一个完全独立的有界上下文中。

【讨论】:

  • 抱歉回复晚了,谢谢。我会接受这是我需要的最接近的答案。我现在明白聚合根会根据上下文而变化。我还找到了一篇不错的文章,进一步帮助我理解了这个问题。 sapiensworks.com/blog/post/2012/04/18/…
【解决方案2】:

如果您需要孩子进行显示/报告/查看/报告,那么一个简单的查询层就可以了。

如果你以任何方式操纵孩子,那么它就有一个一致性边界,听起来很像一个聚合。

尽量不要查询您的域对象。另一个简单的经验法则是不要在另一个聚合中包含聚合引用,而是仅使用引用的聚合的 Id 甚至表示关系的值对象。

【讨论】:

    【解决方案3】:

    实体导航不是域模型的目的。
    聚合根是公开业务操作的实体和值的组合。
    作为副作用,您仍然可以通过 AR 执行一些简单的查询或导航,但是对于复杂的查询,创建和使用查询模型更有效。
    我说的是CQRS

    希望对你有帮助。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-08-26
      • 2011-07-21
      • 1970-01-01
      • 1970-01-01
      • 2021-10-31
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多