DDD:聚合根问题

时间:2009-09-25 08:53:06

标签: domain-driven-design aggregateroot

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

public class Foo{
    private readonly Bar Bar;
}

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

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

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

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

3 个答案:

答案 0 :(得分:17)

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

请注意,虽然OrderItem是Order聚合根的一部分,但您仍然可以单独创建和更新它。但是,如果不参考Order,你就无法得到它。对于你的Bar来说,即使它是Foo的一部分,你也可以得到每个(Foo.Bars)并使用它,或者做Foo.AddBar(新的Bar())。但是如果你需要在没有Foo的情况下获得List,那么Bar不是Foo聚合的一部分。它是一个单独的实体。

嗯,这就是我在这里看DDD的方式,但我当然不是Eric Evans。

答案 1 :(得分:8)

拥有聚合根的原因是:

  1. 他们提供对复合实体的受控和定向访问
  2. 他们可以执行规则以确保整个聚合有效
  3. 我的观点 如果您需要在没有Bar的情况下选择Foo个对象,请使用BarRepository

    <强>可是... 如果您更新Bar,它会破坏其父Foo的验证规则,该怎么办?如果发生这种情况,您应该通过其父Bar访问Foo

    但是,如果您需要访问一堆Bar个对象(例如批处理作业或报告),并且知道 Foos将无法获取破碎,继续通过BarRepository访问它们。

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

答案 2 :(得分:2)

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