将 DDD 应用于罗斯文数据库
Posted
技术标签:
【中文标题】将 DDD 应用于罗斯文数据库【英文标题】:Applying DDD to Northwind database 【发布时间】:2011-01-23 19:02:39 【问题描述】:我想做一些练习并将 DDD 应用于我应用于 Northwind 数据库的域模型。即使 Northwind 是一个例子,我想它也是为了满足一些“虚拟业务”的要求。所以目标是拥有一个尊重 DDD 的领域模型,并且数据存储在 Northiwnd 数据库中。
考虑这个 EF 持久性模型:
(来源:developpeur.org)
请注意,我们只有实体和双向关系。我想要一个真正尊重 DDD 的 DM。而且,我的 DM 模型不需要是我的数据库的镜像
如何在需要时将 des 关系更改为只有一种方式或两种方式。
是否存在可以更改为一对一的多对一或一对多关系?
您将如何为聚合建模?
如果需要,Values 对象、服务和工厂怎么样?
我知道我可能应该看看业务需求,看看模型应该如何改变,但希望得到你的建议。
如果我的问题不清楚,请随时询问详细信息。
提前致谢。
【问题讨论】:
【参考方案1】:一般来说,我很想回答Mu(在禅宗意义上),因为从 DDD 的角度来看,这个场景是错误的。在 DDD 中,我们从业务需求和领域专家开始,并从中派生出领域模型。
虽然这是一个有争议的观点,但数据库几乎只是业务需求的附带产物(几乎总是声明实体必须持久化)。
也就是说,我会尽力做到最好的。
在大多数情况下,订单是一个非常重要的业务对象,显然我们需要了解订单行,包括每一行中的产品,所以看起来我们需要从订单行 (Order_Detail) 到产品。
但是,当给定特定产品时,我们很少需要知道它包含在哪些订单中,因此这表明存在单向关系。我们可以从订单行导航到产品,但不能从产品导航到订单行。
但是,上述分析在更深层次上可能会被证明是错误的。想象一下开发人员和领域专家之间的以下对话:
开发人员: 我们创建了从订单到产品的这种关联,以便我们始终了解特定订单中产品的所有信息。
Exp: 听起来不错,但供应商呢?
开发人员: 也包括在内。
Exp: 那么当我们更换产品的供应商时会发生什么?
开发人员: 这也将隐式反映在订单数据中......
Exp: 这不是我们想要的。我们希望数据反映我们发货时的订单。
在这种情况下,事实证明数据库架构中实际上存在错误。问题可能是由报告引起的,因为业务分析人员可能想要运行关于不同供应商如何影响收入的报告(我知道什么)。
这种情况可能建议完全切断从订单行到产品的关联。订单应保存历史(快照)产品数据,而不是当前产品数据。
我们甚至可以引入一个ProductSnapshot
值对象,它在语义上反映了Product
实体,以便在域模型中对此进行建模。
总而言之,将Order
建模为自身和订单行(与ProductSnapShots
)的聚合似乎越来越合理,但是订单和客户之间的关系呢?
据我目前了解的关联和聚合,关联定义聚合。给定一个订单,我们想了解客户吗?最有可能的。给定一个客户,您想了解订单吗?大概吧。
这表明了一种双向关系,这使得Customer
成为聚合根。这意味着您将拥有CustomerRepository
,但没有OrderRepository
。每次您需要订单时,都必须通过Customer
获取。
在某些情况下,这可能非常有意义,而在其他情况下,这可能非常笨拙。这真的取决于业务需求...
您也可以考虑创建OrderRepository
,但这会侵入Customer
聚合根。如果您这样做,则该命令的责任在哪里变得模糊。如果您从 Order 导航到 Customer,会发生什么? Customer
有一个订单列表,但是如果您从OrderRepository
读取订单,它们是否都填充在内存中?
可能不是,但如果您从CustomerRepository
读取客户,则可能是这样。这里的重点是分析聚合根很重要,一旦定义了聚合,就必须坚持并尊重它。
这导致我偏爱小聚合而不是大聚合,因此在此示例中,我会将聚合限制为 Order
及其订单行,并且 Order
和 @ 之间没有关联987654337@.
Order
和 Customer
之间没有正式关联并不意味着我们根本无法关联它们,但我们需要明确的服务来为我们提供给定的所有订单顾客。我们不能只是从一个导航到另一个。
【讨论】:
这个例子不是最好的。显然,Northwind 数据库是在考虑关系数据的情况下完成的。正如您所说,我们不知道该数据库开始时的要求。但是您的分析非常好且详细。它显示了 DM 应该如何思考和建模。感谢您的时间和详细的答复。以上是关于将 DDD 应用于罗斯文数据库的主要内容,如果未能解决你的问题,请参考以下文章