持久引用聚合之外的非根实体

时间:2012-07-12 08:06:37

标签: domain-driven-design

DDD上的所有材料都将此指定为严格禁止,但我最近遇到了一个令人信服的情况,不这样做。想象一下2个聚合根模板和文档Template --> (1:n) TemplateParam, Document --> (1:n) ParamValue,最后2个根有一个参考Document --> (n:1) Template
鉴于聚合根约束ParamValue不应保留对TemplateParam的引用,只有它可以通过Template聚合根获得的瞬态引用来引用它。现在,如果我想要一个规则强制执行,例如“文档的每个ParamValue应该引用属于其拥有文档引用的模板的有效TemplateParam”。理想情况下在db级别我会让ParamValue有FK到TemplateValue,如何在DDD范例中做到这一点?

2 个答案:

答案 0 :(得分:1)

聚合根源是有原因的。它们充当一组相关实体的单一入口点,以强制执行其不变量。他们确保没有外部对象可以搞砸这些实体,并可能违反它们的不变量。

但是,在您的特定方案中,即使ParamValue持有对TemplateParam的直接引用,TemplateParam也不会被Document聚合中的实体修改。将修改与给定文档的参数关联的,但不会修改参数。

为了确保这种情况,您可以使TemplateParam成为一个不可变的值对象:

(在C#中)

public class TemplateParam
{
    private readonly string name;

    public TemplateParam(string name)
    {
        this.name = name;
    }

    public string Name
    {
        get { return name; }
    }
}

因此,您可以在ParamValue中封装TemplateParam,而不会因TemplateParam的“外部化”而导致模板聚合的不变量之一被破坏。

从技术上讲,这可能违反了DDD的聚合根约束,但只要你保持“外化”实体不可变并且不修改它最初属于的对象图,我不相信它是精神上的一个。

答案 1 :(得分:1)

您可以采用的一种方法是让Template实体具有用于创建Document实例的工厂方法,这可以强制执行所有ParamValue个实例与相应关联的约束TemplateParam。如果文档是不可变的那么你就完成了。否则,您可以通过其关联的模板对文档应用更新。可以直接从文档或ID引用此模板,在这种情况下,封装应用程序服务将在操作需要时检索它。 AR之间的直接引用并不严格违反DDD,实际上蓝皮书指定外部AR可以引用的唯一内容。由于其他考虑因素,例如一致性,性能,ORM映射等,它已成为最近的约束。请查看有效聚合设计的this series of articles以获得一些灵感。