【问题标题】:DDD: aggregate root questionDDD:聚合根问题
【发布时间】:2010-12-01 08:42:21
【问题描述】:

假设我有 2 个实体 - Foo 和 Bar。 Foo 是一个聚合根并包含 Bar。据我了解,它应该是这样的:

public class Foo{
    private readonly Bar Bar;
}

我想为用户提供从定义的列表中选择 Bars for Foos 的功能(并更改它)。

如果存储库应该仅用于聚合根,则意味着将没有 Bar 实体的存储库。

这会导致问题 - 如果没有对 Foo 的引用,就无法独立创建/更新 Bar。

这是否意味着 Bar 应该有一个存储库,尽管没有 Foo 它没有任何意义?

【问题讨论】:

  • 没有愚蠢的问题,只有愚蠢的答案;)顺便说一句,这个问题对我帮助很大

标签: domain-driven-design aggregateroot


【解决方案1】:

如果您想从与 Foo 无关的 Bar 列表中进行选择,则这不是聚合根。例如,如果没有 Order,则无法获取 OrderItems 列表,因此这是单个聚合根 (Order),但您可以获取要分配给 OrderItems 的产品列表,因此 Product 不是 Order 聚合根的一部分。

请注意,虽然 OrderItem 是 Order 聚合根的一部分,但您仍然可以独立创建和更新它。但是,如果不参考 Order,您将无法获得它。您的 Bar 也是如此,即使它是 Foo 的一部分,您也可以获取 each(Foo.Bars) 并使用它,或者执行 Foo.AddBar(new Bar())。但是,如果您需要在没有 Foo 的情况下获取 List,则 Bar 不是 Foo 聚合的一部分。它是一个独立的实体。

嗯,这就是我对 DDD 的看法,但我当然不是 Eric Evans。

【讨论】:

  • 这是有道理的。如果你还有什么要说的——继续。 :)
  • 我学到的东西 - 我的域中有太多聚合根。尽管不应该独立更新实体,但它们还是作为根创建的。更糟糕的是 - 一些根可以替换为值对象。
  • 我想到的另一个建议是,如果您的 Bar 同时是独立的(可以作为单独的列表呈现)和依赖的(在 Foo 中工作) - 也许您实际上有两个这里的实体。一个简短的示例:Group { Name, Price } - 应该在 Order/Product 中并单独显示,但是如果您将其拆分为 Group { Name } 和 ProductGroup { Group, Price },您将分别显示 Group,同时保留 ProductGroup 作为一部分总量。
  • @queen3;我相信我理解你的观点,但你能否为我澄清一些事情。使用不同的示例...客户是具有国家/地区的聚合根。为了设置国家,您需要从国家列表中进行选择...这样也使国家成为总根...正确吗?
  • 好吧,我想说这使 Country 成为一个独立的实体。如果它包含其他实体(例如区域),它将是一个聚合根。那就是如果我正确理解“聚合根”和“实体”是不同的野兽;-) 但它绝对不是客户聚合根的一部分。好吧,在某些情况下,它可能是客户的一部分......例如在用户创建自己的国家的虚拟世界游戏中,一个国家可能是“玩家世界”的一部分。但我想这不是你的情况。
【解决方案2】:

有聚合根的原因是:

  1. 它们提供对复合实体的受控和定向访问
  2. 他们可以强制执行规则以确保整个聚合有效

我的看法: 如果您需要选择没有FooBar 对象,请使用BarRepository

但是…… 如果您更新 Bar,并且它违反了它的父 Foo 的验证规则,该怎么办?如果发生这种情况,您应该通过其父级Foo 访问Bar

但是,如果您需要访问一组 Bar 对象(例如,用于批处理作业或报告),并且您知道 Foos 不会被破坏,请继续并通过BarRepository 访问它们。

请记住,聚合根可以由其他聚合根组成。您可能会发现 Bar 本身就是一个聚合根,这为您提供了 BarRepository 的理由:)

【讨论】:

    【解决方案3】:

    您确定 Bar 需要是一个实体吗?您是否需要在域中对其进行跟踪和更改?如果您可以将其视为值对象,我建议您从服务中获取它,然后将选定的值对象“连接”到 Foo 实体。通过下拉列表获取即时信息。

    【讨论】:

    • 为什么实体不能通过服务获取并连接到Foo?
    • 如何在没有实体上下文的情况下创建/更新值对象?那不是将服务屏蔽为值对象不应该具有的存储库吗?
    • 让我解释一下我是怎么做到的;我需要一种从持久层获取数据的方法。我可以使用 DTO 来获取数据,但我更愿意使用值对象,因为这样我就可以使用域中的对象,而无需从 DTO 映射到值对象。我正在使用的对象是聚合根中的一个类,在你的例子中是 Bar。如果我要为实体执行此操作,我想我会使用 DTO(通过服务获取)来填充列表(组合框等),当我选择了正确的 Bar 时,我会要求存储库为我获取完整的对象从聚合根。希望这是有道理的。
    • 我想知道这个解决方案是否可以完全适用于我关于验证和基于聚合外部数据选择默认值的问题。 stackoverflow.com/questions/5454521/…
    猜你喜欢
    • 2016-03-21
    • 2015-01-04
    • 1970-01-01
    • 1970-01-01
    • 2012-02-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多