2

我一直在做 DDD 的一个小项目。我到处都看到值对象是不可变的,因此,你不能修改它。只有实体。

我将使用每个人都使用的示例。地址。假设Address 是Customer 实体的 VO(也是根聚合)。如果用户更新他的 Address,这在任何购物车场景中都有效,那么我应该怎么做?我必须修改那个 VO 地址才能将其保存到数据库中。意思是,这个 VO 必须以某种方式具有身份,以便我在数据库中识别它。除非 NHibernate 使用映射来处理它,对。LinqToSql 你不是这种情况。或者我想我必须创建一个新的聚合,其中地址是一个实体?然后几乎在我的聚合中需要地址的任何地方都有一个地址副本?

然而。我仍然无法包装整个 Entity/VO 概念。在我看来,就像在数据库中有表示的所有内容一样,即使您将其用作模型中的 VO,它在某种程度上也是一个实体,因为为了让您持久保存它,您需要某种 KEY 来在数据库中识别它.

归根结底,所有值对象的数据(大部分)都来自数据库。所以我仍然不明白在数据更新的情况下如何使它们不可变。

经过两个月的紧张阅读,我发现整个 DDD 是一个巨大的矛盾问题。阅读所有这些博客,你会明白我在说什么。不幸的是,那里有零演示应用程序,您可以将其用作榜样或指导。它们都受到开发者偏好的影响。然后他们最终攻击了对方的博客。一夜之间-DDD-Guru 的博客确实有助于解决整个社区的困惑。

感谢您的光临。期待建设性的讨论。

4

4 回答 4

8

我相信您的困惑在于数据库行标识和与 DDD 中的实体相关联的标识概念之间的人为耦合。它们肯定是相关的,因为实体将具有在数据库中表示为标识列的相应标识。但是,仅仅因为某物具有作为数据库行的身份,并不意味着该对象具有 DDD 意义上的身份。

在您的地址示例中,包含地址 VO 的值通常与客户实体存储在同一行中。通过这种方式,地址是一个值对象,因为它没有存储在自己的行中并且没有标识。更新地址时,您会更改客户实体上的地址属性值,这反过来会反映在数据库行中。

在某些情况下,值对象将存储在自己的行中。例如,在典型的销售订单模型中,订单是一个实体(聚合根),而行项目是值对象。虽然行项目是 VO,但在关系模型中,它们存储在自己的表中,并且很可能具有主键。然而,在域模型中,VO 与订单实体相关联,并且在该实体之外没有身份。

于 2012-11-20T03:15:22.660 回答
3

实际上,周围有很多演示,可能在您想象的每一种技术中,从 Java 中的原始 DDDSample开始。此示例至少有两个 .NET 端口:NDDDDDDSample.Net

至于 VO 和持久性,如果您将 VO 视为一个对象,它包含代表实体的表中的几列,那么这很容易(例如 Money VO 包装金额和货币)。当您想要在 SQL 级别规范化数据并为 VO 创建表(而不是将它们嵌入实体表中)时,问题就开始了。我不知道该问题的好的解决方案,但幸运的是,在使用关系存储实现 DDD 时,这不是一个好的做法。为什么?最重要的原则之一是聚合应尽可能相互独立。使用此规则在对象模型中共享 VO类是可以的,但在数据存储中共享 VO则不行,因为此单个表可能会成为例如锁定瓶颈。

简而言之:当使用 SQL 数据库存储域模型时,请考虑不要对聚合之间的模型进行规范化。

于 2012-11-17T06:43:08.500 回答
2

您也可以尝试从现实世界(或领域)的角度来看这些问题。地址很少改变。更常见的情况是客户更改了他的地址(例如他正在搬到另一个公寓),而地址本身也发生了变化。

考虑到这一点,地址必须是一个值对象。

于 2013-05-21T12:33:57.203 回答
0

嘿,我看到这是一个非常古老的问题,但我正在寻求 DDD 并且有一些类似的问题。

我使用 DDD 找到的解决方案的最佳途径是忘记数据库并考虑模型。因此,在上述情况下,您有一个客户和一个地址 VO,并且您想要一个客户的地址列表,例如在电子商务网站的场景中,客户有多个送货地址可供选择。好吧,在域模型的真实上下文中,这些地址不仅仅是地址 VO,它们是 CustomerShippingAddress 实体。

因此,您的 CustomerShippingAddress 实体有一个身份,并且它有一个地址 VO。也许它还有一些其他的东西,比如 IsDefault 和 DateAdded 等

我建议您只能从传入地址 VO 的客户实体实例化 CustomerShippingAddress,然后您会返回 CustomerShippingAddress 的聚合根,其中包含对客户的 ID 引用。

这样您就可以维护您的 AddressVO,但可以在多个场景中重用该 VO。

当客户选择地址作为订单的送货地址时,他们选择的 AddressVO 将应用于订单聚合。这意味着该订单上的送货地址被及时锁定到当时的地址 VO。CustomerShippingAddress 稍后可能会被修改,但送货地址VO 在订单上将永远保持不变。

于 2016-03-17T13:37:40.993 回答