Domain driven design 持久化引用聚合外部的非根实体

Domain driven design 持久化引用聚合外部的非根实体,domain-driven-design,Domain Driven Design,DDD上的所有材料都明确指出这是一个严格的“不”字,但我最近遇到了一个场景,它让我有理由不这样想。想象两个聚合根模板和文档,其中Template-->(1:n)TemplateParam,Document-->(1:n)ParamValue,最后两个根都有一个引用Document-->(n:1)Template 给定的聚合根约束ParamValue不应保留对TemplateParam的引用,只有它可以通过通过Template聚合根获取的临时引用来引用它。现在,如果我想强制执行一条规则,比如“文档

DDD上的所有材料都明确指出这是一个严格的“不”字,但我最近遇到了一个场景,它让我有理由不这样想。想象两个聚合根模板和文档,其中
Template-->(1:n)TemplateParam,Document-->(1:n)ParamValue
,最后两个根都有一个引用
Document-->(n:1)Template


给定的聚合根约束
ParamValue
不应保留对
TemplateParam
的引用,只有它可以通过通过
Template
聚合根获取的临时引用来引用它。现在,如果我想强制执行一条规则,比如“文档的每个ParamValue都应该引用一个有效的TemplateParam,该TemplateParam属于其所属文档引用的模板”。理想情况下,在db级别,我会让ParamValue将FK设置为TemplateValue,如何在DDD范式中实现它???

聚合根的存在是有原因的。它们充当一组相关实体的单个入口点,以强制执行它们的不变量。它们确保没有外部对象会弄乱这些实体,并可能破坏它们的不变量

但是,在特定场景中,即使ParamValue直接引用TemplateParam,TemplateParam也不会有被文档聚合中的实体修改的风险。将修改与给定文档的参数关联的值,但不会修改参数

要确保情况属实,可以将TemplateParam设置为不可变值对象:

(用C#表示)

公共类TemplateParam
{
私有只读字符串名称;
公共模板参数(字符串名称)
{
this.name=名称;
}
公共字符串名
{
获取{返回名称;}
}
}
因此,您可以将TemplateParam封装在ParamValue中,而不会因为TemplateParam的“外部化”而破坏模板聚合的不变量之一


从技术上讲,这可能违反了DDD的聚合根约束,但我不认为这是一个精神上的约束,只要您保持“外部化”实体是不可变的,不修改它原来所属的对象图。

一种方法是让
模板
实体有一个工厂方法来创建
文档
实例,它可以强制所有
ParamValue
实例与相应的
TemplateParam
关联。如果文档是不可变的,那么就完成了。否则,您可以通过文档的关联模板将更新应用于文档。该模板可以直接从文档中引用,也可以使用ID引用,在这种情况下,封装应用程序服务将在操作需要时检索该模板。ARs之间的直接引用并不是对DDD的严格违反,事实上,蓝皮书规定只有这些东西可以被外部ARs引用。最近,由于一致性、性能、ORM映射等其他考虑因素,它已经成为一个约束。请看一下有效的聚合设计,以获得一些启示