Domain driven design DDD,可以让多个聚合根在有界上下文中共享相同的标识吗

Domain driven design DDD,可以让多个聚合根在有界上下文中共享相同的标识吗,domain-driven-design,aggregateroot,bounded-contexts,Domain Driven Design,Aggregateroot,Bounded Contexts,在一个有界的上下文中有许多这样的聚合根可以吗 Product ProductID : GUID Name : string Price : float ProductPromotion ProductID : GUID Discounted : float ProductShortName ProductID : GUID ShortName : string 我不知道这会打破有界语境的规则,而这些是不同种类的产品,但在一个语境中 在DDD场景中,

在一个有界的上下文中有许多这样的聚合根可以吗

Product
   ProductID : GUID
   Name : string
   Price : float

ProductPromotion
   ProductID : GUID
   Discounted : float

ProductShortName
   ProductID : GUID
   ShortName : string
我不知道这会打破有界语境的规则,而这些是不同种类的产品,但在一个语境中


在DDD场景中,每个聚合根都应该有自己的唯一ID,如果我正确理解了您的场景,那么这似乎是缺失的,您似乎希望所有3个类都是根。所以,如果你的设计是这样的:

Product <ROOT>
   ProductID : GUID
   Name : string
   Price : float

ProductPromotion <ROOT>
   PromotionID: GUID
   ProductID : GUID
   Discounted : float

ProductShortName <ROOT>
   NameID: GUID
   ProductID : GUID
   ShortName : string
就其本身而言,这种设计不会损害聚合或有界上下文原则。应该允许一个聚合保存对另一个聚合根的id的引用,就像无数购物车示例中的LineItem保存对ProductID的引用一样

您不应该做的事情是在另一个集合中保存对整个集合的完整引用

但是,在设计聚合时,您应该始终思考您的目标是什么。是的,它们应该很小,但它们也必须传达一个目标。通常,它们被设计为强制执行某些不变量,而这些示例似乎并没有实现这一目标


也许你的例子对于这个问题过于简化了,我无法对其进行真正的评估,但在我看来ProductPromotion和ProductShortName并不是完整聚合的理想候选。在DDD场景中,每个聚合根都应该有自己的唯一ID,如果我是正确理解您的场景,您似乎希望所有3个类都是根。所以,如果你的设计是这样的:

Product <ROOT>
   ProductID : GUID
   Name : string
   Price : float

ProductPromotion <ROOT>
   PromotionID: GUID
   ProductID : GUID
   Discounted : float

ProductShortName <ROOT>
   NameID: GUID
   ProductID : GUID
   ShortName : string
就其本身而言,这种设计不会损害聚合或有界上下文原则。应该允许一个聚合保存对另一个聚合根的id的引用,就像无数购物车示例中的LineItem保存对ProductID的引用一样

您不应该做的事情是在另一个集合中保存对整个集合的完整引用

但是,在设计聚合时,您应该始终思考您的目标是什么。是的,它们应该很小,但它们也必须传达一个目标。通常,它们被设计为强制执行某些不变量,而这些示例似乎并没有实现这一目标


也许你的例子对于这个问题过于简化了,我无法对其进行真正的评估,但在我看来ProductPromotion和ProductShortName并不是完整聚合的理想候选方式。我在两个不同的应用程序中使用了该模式,效果很好。 我认为,如果聚合中有一个状态,那么它的所有属性都可以让您检查它可以工作的命令的所有不变量。 如果要在聚合的命令方法内进行验证,需要在另一个方法内存储属性,则会出现问题。 在另一个响应中,我了解到每个聚合都有一个唯一的ID,在本例中,聚合的ID可以被视为AggregateType、GUID。 最终,您只是将单个聚合存储在多个分区中,作为一个聚合是一致性/事务的边界,直到您的命令修改使用原子操作存储的单个部分为止。您的聚合不会违反任何规则。
为了了解它是否适合您的问题,您还必须检查这些聚合是如何读取的,因为如果您需要读取整个聚合状态,则根据持久性技术,最终可能会对存储进行多个查询,以检索所有这些查询,从而降低性能,根据您的使用情况,这可能是可以接受的,也可能是不可以接受的。在我的案例中,一个是使用事件源开发的,因此读取模型是作为单个读取操作完成的,在第二个案例中,通过一些缓存帮助,还可以执行多个查询。性能还可以。

我在两个不同的应用程序中使用了该模式,效果很好。 我认为,如果聚合中有一个状态,那么它的所有属性都可以让您检查它可以工作的命令的所有不变量。 如果要在聚合的命令方法内进行验证,需要在另一个方法内存储属性,则会出现问题。 在另一个响应中,我了解到每个聚合都有一个唯一的ID,在本例中,聚合的ID可以被视为AggregateType、GUID。 最终,您只是将单个聚合存储在多个分区中,作为一个聚合是一致性/事务的边界,直到您的命令修改使用原子操作存储的单个部分为止。您的聚合不会违反任何规则。 为了了解它是否适合您的问题,您还必须检查这些聚合是如何读取的,因为如果您需要读取整个聚合状态,则根据持久性技术,最终可能会对存储进行多个查询,以检索所有这些查询,从而降低性能,根据您的使用情况,这可以接受,也可以不接受
案例在我的案例中,一个是使用事件源开发的,因此读取模型是一个单一的读取操作,在第二个案例中,通过一些缓存帮助还可以执行多个查询,性能还可以。

我编辑了这个问题。最后一个问题是我真正需要的东西。但是如果我这样设计,它可能会通过只使用域设计来解决问题。答案基于以前的版本。“我会检查新的。”佩德罗戈斯在交易所问。你可以在那里回答:我已经编辑了这个问题。最后一个问题是我真正需要的东西。但是如果我这样设计,它可能会通过只使用域设计来解决问题。答案基于以前的版本。“我会检查新的。”佩德罗戈斯在交易所问。您可以在这里回答:通常,如果我进行设计,我不会让这些聚合根在同一个有界上下文中。这不好吗?但是,按照您提到的方式,我不能使用promotionID引用promotionID,这是必需的,因为所有这些逻辑都发生在流程管理器中,不利于从读取模型中查询:*为什么它们不在同一个有界上下文中?看起来应该是这样。我认为你最好的做法是在这一点上重新设计你的聚合。很明显,它们目前并没有帮助您实现域规则。你有几个选项很难在评论中解释,但我会把其中的一些去掉:1你可以让你的产品成为促销聚合的工厂,并确保促销ID在创建时与productID匹配。2似乎你最好有一个定价汇总,集中产品的所有价格+折扣逻辑,包括主动折扣、临时折扣等。3你可以通过阅读模型找到促销品,始终意识到读取模型可能过时,并且最终是一致的。通常,如果我进行设计,我不会让这些聚合根在相同的有界上下文中。这不好吗?但是,按照您提到的方式,我不能使用promotionID引用promotionID,这是必需的,因为所有这些逻辑都发生在流程管理器中,不利于从读取模型中查询:*为什么它们不在同一个有界上下文中?看起来应该是这样。我认为你最好的做法是在这一点上重新设计你的聚合。很明显,它们目前并没有帮助您实现域规则。你有几个选项很难在评论中解释,但我会把其中的一些去掉:1你可以让你的产品成为促销聚合的工厂,并确保促销ID在创建时与productID匹配。2似乎你最好有一个定价汇总,集中产品的所有价格+折扣逻辑,包括主动折扣、临时折扣等。3你可以通过阅读模型找到促销,始终意识到阅读模型可能过时,并且最终是一致的。