【问题标题】:DDD valueObject and database schemaDDD valueObject 和数据库模式
【发布时间】:2014-12-31 14:12:22
【问题描述】:

到 2014 年底,我想到了一个简单的问题。 我想更多地使用“DDD”,我目前正在尝试各种用例以了解有关 DDD 的更多信息。

我目前的用例如下:

  • 我们有一个新的数据库模式,它使用我们公司的经典模式:将我们的命名表建模为“id/code/label”。我认为这是一个非常经典的案例,例如使用 hibernate。

但是在 OO 世界中,当使用 JDBC 或 QueryDSL 等 API 时,这种简单的事情会变得“复杂”。我需要通过其代码获取对象,检索其 id 或加载完整对象,然后将其设置为另一个对象中的一对一关系。

我想知道:

  • 这种命名法可以是一个枚举(或一个具有字符串 cosnatnts 的类,具体取决于开发人员)。在 DDD 术语中,它是我的 ValueObject
  • 数据库中的 id /code / label 不是 i18n 友好的(它不是先决条件),所以我看不出它的优势。除非表可以动态更新并且用例是“在从该表加载的组合框中选择一些东西并与另一个对象建立关系:但这都是因为如果您有必须应用的业务规则,您需要知道新代码等等)。

我的问题是:

  • 您是否经常在数据库模型中使用 id / ocde / label 模式。
  • 您如何为您的命名数据建模? (国家可能不是最好的例子:)但不管你如何建模它?不用多想,我会说国家的数据库表;但是对于某些状态:“有效,等待验证,被拒绝”?
  • 您是否使用此模式为您的 valueObject 建模?
  • 还是您使用大量枚举并且只将它们的 toString(或序数)存储在数据库中?

在 Java OO 对象世界中,我目前认为操作从数据库加载的对象的枚举更容易。例如,我需要构建存储库来加载它们。将它们用作枚举将非常简单。我正在这里寻找一些舒适的地方,或者我是否遗漏了一些如此明显的东西?

谢谢

2015 年见!

更新 1: 我们可以创建一个“预算”,第一个标记为初始,下一个标记为“更正”(带有增量)。例如,我们可以有一个预算列表:“初始预算”、“修正预算 #1”、“修正预算 #2”。

为此,我们有这样的数据库设计:一个预算表,一个版本预算,两者之间有一个外键。版本预算仅包含一个 ID、一个代码和一个标签。

就个人而言,我想删除此表。我没有看到这种结构的优点。从 OO 的角度来看,当我创建预算时,我可以查询数据库以查看是否需要创建初始预算或修正预算(使用计数查询),然后我可以将正确的枚举设置为我的新预算。但是对于当前的设计,我需要使用我想要的 CODE 查询数据库,选择 ID 并设置 ID。所以是的,它确实是面向数据库的。 DDD 部分在哪里? ValueObject 是描述、量化某些东西的东西。就我而言,对我来说似乎很好。版本描述了我的预算的当前状态。我可以比较两个版本,但检查它们的代码,它们没有生命周期(我特别不想要这个)。

你如何处理这种类型的用例?

这只是一个简单的例子,因为我发现如果你问数据库管理员,他肯定会说一切似乎都很好:使用主键、建模关系、强制约束、使用外键和避免数据重复。

再次感谢 Mike 和 Doctor 的 cmets。

【问题讨论】:

  • 如果您的对象具有身份(即代码),您将在此之前检索它,那么它就不是值对象。
  • 我 100% 确定这一点。例如,如果我有一张里面有 TAX 的表。真正的基本结构可以是 ID / CODE / PERCENTAGE / LABEL。使用这种结构时,20% TAX 和另一个 20% TAX 有什么区别?我认为没有。如果我们添加时间属性,也许它可以是一个实体,但只有一个百分比和一个用于获取它的代码,它不是一个 valueObject 吗?
  • 不,值对象没有身份,如果没有实体关联就无法存在。在我看来,我们在谈论参考数据,所以这可能很有用:stackoverflow.com/questions/5478253/…。如果附加到某物(订单或类似物品)时价值没有改变,那么此时订单的税可能是一个价值对象。
  • 你想使用 D(omain)DD 但你的问题都是关于数据库的。这是你的问题,你还没有理解 DDD 是关于什么的。您当前的心态与 DDD 完全无关。我可以说,你现在正在使用 DDD 反模式。
  • @MikeSW:我同意你的看法。我不是设计数据库的人。我谈论数据库设计是因为我想改变它,因为它是很多人关注的焦点,尤其是在我现在的公司。我的问题是如何处理,向我的同事解释这些概念等。

标签: java database domain-driven-design


【解决方案1】:

我将以您所在国家/地区为例。在大多数情况下,国家将是一个值对象。没有任何东西会引用国家实体,并且应该知道如果国家的价值发生变化,它仍然是同一个国家。事实上,国家可以表示为一个枚举,以及一​​些将 Iso3 转换为有用的显示文本的讨厌的资源查找功能。我们所做的是,我们将其定义为带有 iso3、displayname 和其他一些静态信息的值对象类。现在,在这个值对象中,我们定义了一种“幂枚举”(我在这里仍然错过了一个标准术语)。实现国家/地区值对象的类为其每个值(针对每个国家/地区)获取私有构造函数和静态属性,以及从 int 到 int 的显式转换运算符。现在您可以将其视为编程语言的普通枚举。除了拥有更多属性字段之外,普通枚举的优势在于,它还可以拥有方法(当然是查询方法,不会改变对象的状态)。您甚至可以使用多态性(某些国家的行为与其他国家不同)。您还可以从数据库表中加载枚举的内容(然后不使用静态方法,而是使用静态 lookupByIso3 方法)。

您也可以使用其他一些“类似枚举”的值对象来实现这一点。想象一下货币(它可能具有实现多态的转换方法)。不过,每日汇率的处理是另一回事。

如果值的集合不是固定的(例如另一个值对象候选对象,如邮政地址),那么它不是一个值对象枚举,而是一个可以用您想要的值实例化的标准值对象。

要决定是否可以将某物作为值对象,您可以使用以下问题:您想要复制语义还是引用语义?如果您更改了对象的属性,那么您使用它的所有地方都应该更新,还是应该保持原样?如果是后者,那么“更改”对象是一个新的和不同的值对象。另一个问题是,如果您需要跟踪对象的更改,并意识到尽管值发生了变化,它仍然是“相同的”。如果你有一个值对象,你只希望特定的实例存在,它就是上面描述的一种枚举。

这对你有帮助吗?

【讨论】:

  • 国家/地区可能有大量的属性,例如电话代码、货币、时区、语言、欧盟成员国与否、增值税号码前缀等。那么你怎么能确定你永远不需要这个呢?
  • 我认为在 DDD 中你不会用你可以从现实中想象的所有属性来模拟国家,而只是有界上下文需要的属性。在另一个有界上下文中,您将使用那里需要的其他属性对其进行建模。此外,您描述的事物是不同的概念,而不是国家的简单属性。我所说的“国家”是指国家本身。不像人口那样统计它。但是,即使您必须更改它的某些属性,问题仍然是这之后是否需要“相同”,或者您是否可以将其作为“新”值使用。
猜你喜欢
  • 1970-01-01
  • 2017-08-07
  • 1970-01-01
  • 2017-04-11
  • 1970-01-01
  • 1970-01-01
  • 2013-08-13
  • 2016-05-01
  • 1970-01-01
相关资源
最近更新 更多