Domain driven design 正在破坏DDD聚合根引用规则

Domain driven design 正在破坏DDD聚合根引用规则,domain-driven-design,aggregateroot,Domain Driven Design,Aggregateroot,根据我的阅读资料,DDD中的建议是聚合根不应包含对另一个聚合根的引用。最好只保留对身份证的引用。我正在试图弄清楚我的案子是否有理由违反规则 以会计系统为例,假设您将发票作为聚合根。该发票具有行和付款,这些可以是根目录下的实体。但是,发票也会分配给买方和供应商。行项目还链接到可以有预算的帐户。买方、供应商、预算,这些都是他们自己的权利,需要管理和有自己的规则集的实体。但它们也会影响处理发票时的业务规则。当然,我可以创建一个域服务,并使用它分别加载内容,但这不只是让我的域对象性能下降,性能更差吗 如

根据我的阅读资料,DDD中的建议是聚合根不应包含对另一个聚合根的引用。最好只保留对身份证的引用。我正在试图弄清楚我的案子是否有理由违反规则

以会计系统为例,假设您将发票作为聚合根。该发票具有行和付款,这些可以是根目录下的实体。但是,发票也会分配给买方和供应商。行项目还链接到可以有预算的帐户。买方、供应商、预算,这些都是他们自己的权利,需要管理和有自己的规则集的实体。但它们也会影响处理发票时的业务规则。当然,我可以创建一个域服务,并使用它分别加载内容,但这不只是让我的域对象性能下降,性能更差吗

如果我可以持有对实体的引用,我就可以运行一个查询,只需获取我需要的所有数据(我将使用.NET中的实体框架核心)。如果我继续持有对外键的引用,那么我需要为我需要的其他聚合中的每一个运行调用。然后,我的域对象就不能再像它自己那样丰富了,因为如果没有外部协调器(域服务),它无法处理它所需要的所有业务规则


我想知道的另一件事是,这些项根本不会被聚合根修改,并且在这种情况下基本上是只读的,这是否意味着我可以用更有限的模型(严格的最小值)将它们放在同一个聚合中,然后它们也会有自己的聚合根(例如,我有两个预算实体,一个在发票根目录下,一个在预算根目录下)。我的想法是,DDD并不真正关心底层存储,因此这似乎是一个有效的a选项。如果买方/供应商/预算的实体是发票聚合根下的实体,则它们的聚合根版本也可能会大大简化,而它们的聚合根版本会复杂得多,对吗e属性、业务逻辑等。

我认为最好的选择可能是通过服务来实现。发票需要来自其他域的部分逻辑,而不是全部逻辑。如果这些实体/聚合根不需要修改,您只需要一些过程的结果。此外,您可以使用那里的
六边形体系结构
和b从域之间的通信方式中提取域。通信可以通过http、队列以及代码中的引用进行。通过将聚合根添加到其他聚合,您将坚持使用最后一个聚合

我想知道的另一件事是,这些项根本不会被聚合根修改,并且在这种情况下基本上是只读的,这是否意味着我可以用更有限的模型(严格的最小值)将它们放在同一个聚合中,然后它们也会有自己的聚合根(例如,我有两个预算实体,一个在发票根目录下,一个在预算根目录下)

你应该回顾一下Pat Helland的论文

重要的问题不是是否要修改数据,而是在主聚合运行时是否需要锁定数据以防修改

如果数据不需要被锁定以防修改,那么您可以将其视为外部数据,也就是说,您将所需数据的未锁定副本传递给聚合。粗略地翻译,这意味着您的应用程序代码获取数据的副本,然后将其作为参数传递给聚合

如果确实需要对数据进行锁定以防止修改,那么您实际上已经在内部获得了数据。因此,现在您需要了解锁定机制将如何工作:

如果您的域模型在单个执行线程中运行,那么您可能不会有问题:该线程一次只能做一件事这一事实意味着您有效地锁定了“一切”

如果所有数据都存储在同一个RDBMS中,那么您可以将数据作为事务的一部分“锁定以读取”,这样,如果同时进行修改,事务本身将失败

近年来,我们一直试图在一个具有多个执行线程和多个数据存储的环境中工作,但这两个约束都不成立。因此,人们倾向于重新设计其聚合以支持这种情况:如果在更改值B时必须锁定值A以防修改,则And B必须是同一聚合的一部分(并受同一聚合根的保护)

这里“必须”的定义相当糟糕。另一个可能更好的框架是思考“失败对业务的影响是什么?”()。如果失败的成本很低,那么我们可以使用未锁定的数据副本,而不是尝试将数据整合到单个聚合中

DDD中的建议是,聚合根不应持有对另一个聚合根的引用。最好只持有对ID的引用。我正在试图弄清楚我的案例是否有理由违反规则

不需要。聚合的目的是将业务逻辑和实现此业务逻辑所需的数据封装在“事务”中方式。您不能允许在根控制之外修改聚合的该部分。如果您的聚合A需要聚合B来执行其工作,您可以说聚合B是聚合A的一部分。因为聚合B可以自行更改(这就是为什么它是聚合),这意味着聚合A的一部分在其根的控制之外发生了变化。对不起,这是一个复杂的句子

有多种原因可以解释为什么你会发现自己的聚合需要的不仅仅是anot的Id