Domain driven design 如何检查将子DDD实体添加到父(树状结构)实体是否不';不要在另一棵树上骑自行车

Domain driven design 如何检查将子DDD实体添加到父(树状结构)实体是否不';不要在另一棵树上骑自行车,domain-driven-design,Domain Driven Design,我正在对一个领域进行建模,其中实体是业务服务的包,可以由其他包组成——树结构。我在为避免周期设计域逻辑时遇到一些问题 假设我们有实体(类“Package”的对象)PackageA,它有子项(PackageB和PackageC)。我们还有儿童套餐B。 现在,我们希望将PackageA作为其子项添加到PackageB中——我们通过从PackagePostory获取PackageB并使用PackageB::addChildPackage()方法来实现这一点。但在此之前,我们需要确保添加此包不会在其他树

我正在对一个领域进行建模,其中实体是业务服务的包,可以由其他包组成——树结构。我在为避免周期设计域逻辑时遇到一些问题

假设我们有实体(类“Package”的对象)PackageA,它有子项(PackageB和PackageC)。我们还有儿童套餐B。 现在,我们希望将PackageA作为其子项添加到PackageB中——我们通过从PackagePostory获取PackageB并使用PackageB::addChildPackage()方法来实现这一点。但在此之前,我们需要确保添加此包不会在其他树中执行任何循环(在本例中会)。问题是如何在DDD中实现这一点

我考虑将包添加到域服务,这样我就可以获得当前与我要修改的包相关的所有包,并检查它们是否没有周期

你认为这是个好主意吗

我考虑将包添加到域服务,这样我就可以获得当前与我要修改的包相关的所有包,并检查它们是否没有周期

你认为这是个好主意吗


是的,你能做到。添加为
包提供验证的
PackageServices
类对域的描述有一定意义。

聚合根不应包含对另一个聚合根实例的引用。您应该使用
Id
或包含
Id
和一些额外有趣信息的值对象间接引用其他聚合

您的案例似乎符合分类结构,您可以将事件模型与主聚合分开。无论哪种方式,您都需要获得聚合所属的整个层次结构,以检查是否存在循环。但是,如果您和其他用户正在做的事情会创建一个周期,则不能保证您不会同时与其他用户一起创建一个周期

对于某些独特的属性(如电子邮件地址),情况大致相同。在这种情况下,它可以像在数据存储上创建唯一约束一样简单

在循环依赖的情况下,它不会像创建约束那样简单,对于不支持唯一约束的数据存储也是如此

在这种情况下,您需要使用一些流程管理器并执行几个步骤。我们可能希望通过在层次结构中创建项之前检查循环来防止明显的循环。提交工作单元(比如事务)后,您可以发送一条消息来验证新条目。第二步将再次检查循环,因为其他人可能与您一起创建了无效状态。如果您有一个周期,那么最后输入的项目“丢失”,并被删除,并发布一个排序通知,以使该决定为人所知

另一种方法是尝试使用一些锁定策略来防止创建循环。根据您的设计,它必须具有正确的颗粒。如果您有各种独立的层次结构,它们可以锁定在根级别。根目录将是没有父目录的
。提交后,您将释放锁。如果您只有一个层次结构,那么您可能仍然可以锁定它,并且在任何时候只允许对层次结构进行一次更改


为此使用域服务似乎是一种方法,但这本身并不能完全解决您的问题。更多的是关于这项服务将要做什么。

我是DDD的新手-你可能知道,你的评论对我来说是无价的。:)关于单独建模分类结构-可能我可以创建一个树,其中节点的值将是agregate的id。我正在考虑创建一个域服务,在这个域服务中,root用户可以相互“交谈”@Eben Roux您对这个想法有何看法?我不会重新发明轮子,可能会使用一个树库,即(我来自PHP world:),因此,外部库和我的核心域之间的一些额外耦合就成了等式。这是个好主意吗?尽量让你的域名不受任何基础设施的影响。如果引用的库将增加重要的价值,那么尝试一下,看看结果如何。聚合确实是交互的,通常使用域服务,有时使用执行用例的应用程序服务进行交互。在未知领域给出100%正确的建议总是很棘手的,但我建议尝试几种技术,找出最有效的方法。你甚至可以稍后再来,找到更好的解决方案。正如蓝皮书中所说的,在找到合适的型号之前,你倾向于选择几个型号。