一般来说,我很想回答Mu(在禅宗意义上),因为从 DDD 的角度来看,这种情况是错误的。在 DDD 中,我们从业务需求和领域专家开始,并从这些领域派生出领域模型。
尽管这是一个有争议的观点,但数据库几乎只是业务需求的附带产物(几乎总是声明实体必须持久化)。
也就是说,我会尽力做到最好。
在大多数情况下,订单是一个非常重要的业务对象,显然我们需要了解订单行,包括每一行中的产品,所以看起来我们需要从订单行 (Order_Detail) 到产品的关联。
但是,当给定特定产品时,我们很少需要知道它包含在哪些订单中,因此这表明存在单向关系。我们可以从订单行导航到产品,但不能从产品导航到订单行。
然而,在更深层次上,上述分析可能会被证明是错误的。想象一下开发人员和领域专家之间的以下对话:
Dev: 我们创建了从订单到产品的这种关联,以便我们始终了解特定订单中产品的所有信息。
Exp: 听起来不错,但是供应商呢?
开发人员: 这也包括在内。
Exp: 那么当我们改变产品的供应商时会发生什么?
开发人员: 这也将隐含在订单数据中……
Exp: 那不是我们想要的。我们希望数据反映我们发货时的订单。
在这种情况下,事实证明数据库架构中实际上存在错误。问题可能是由报告引起的,因为业务分析人员可能想要运行关于不同供应商如何影响收益的报告(我知道什么)。
这种情况可能建议完全切断从订单行到产品的关联。订单应保存历史(快照)产品数据,而不是当前产品数据。
我们甚至可以引入一个在语义上反映实体的ProductSnapshot
值对象,以便在域模型中对此进行建模。Product
Order
总而言之,将其建模为自身和订单行(带有 )的聚合似乎越来越合理ProductSnapShots
,但是订单和客户之间的关系呢?
据我目前了解关联和聚合,关联定义聚合。给定一个订单,我们想了解客户吗?最有可能的。给定一个客户,您想了解订单吗?大概。
这表明了一种双向关系,这使得Customer
Aggregate Root。这意味着您将有一个CustomerRepository
,但没有OrderRepository
。每次您需要订单时,都必须通过Customer
.
在某些情况下,这可能非常有意义,而在其他情况下,这可能非常笨拙。这真的取决于业务需求......
您也可以考虑创建一个OrderRepository
,但这会侵入Customer
聚合根。如果您这样做,则该命令的责任在哪里变得模糊。如果您从 Order 导航到 Customer,会发生什么?Customer
有一个订单列表,但是如果您从OrderRepository
?
可能不是,但如果您从CustomerRepository
. 这里的重点是聚合根的分析很重要,一旦你定义了一个聚合,你就必须坚持并尊重它。
这使我更喜欢小聚合而不是大聚合,因此在此示例中,我会将聚合限制为Order
及其顺序线,并且 和 之间没有Order
关联Customer
。
Order
和之间没有正式的关联Customer
并不意味着我们根本无法将它们联系起来,但我们需要明确的服务来为给定客户提供所有订单。我们不能只是从一个导航到另一个。