【发布时间】:2010-10-31 06:19:00
【问题描述】:
值对象没有标识。 ORM 需要身份来更新数据库。
如何欺骗 ORM?
(将值对象的 Id 标记为内部将不起作用,因为 ORM 存在于不同的程序集中并将其移动到同一程序集是不可接受的)。
提前致谢。
【问题讨论】:
标签: domain-driven-design identity value-objects
值对象没有标识。 ORM 需要身份来更新数据库。
如何欺骗 ORM?
(将值对象的 Id 标记为内部将不起作用,因为 ORM 存在于不同的程序集中并将其移动到同一程序集是不可接受的)。
提前致谢。
【问题讨论】:
标签: domain-driven-design identity value-objects
一个 VO 属于一个实体。 我们将使用Entity's ID(business ID)来追踪VO。
一个VO也可能包含其他实体/VO,它只是代表OO,封装。 举个例子,E-R,1:N,我们可以用Union Table来持久化它。
专注于业务,而不是那些概念。
【讨论】:
前面的答案中提到的所有持久化值对象的选项——例如将值对象属性扁平化为它们所属的实体表的列,或者通过包含数据模型的唯一 id 将它们持久化到单独的表中——是有效且解释清楚。当然,这些选项通常独立于特定的底层数据库技术而适用,这是一个很大的优势。
但我认为至少值得一提其他一些选项,这些选项在许多情况下已经足够且易于实施:
以 JSON 表示形式存储值对象
这当然取决于您的技术限制,但现在许多数据库以及 ORM 解决方案甚至为 JSON 表示提供内置支持。有些甚至包括搜索选项。如果您不希望有大量项目,您甚至可以将此方法用于实体内的值对象列表,方法是将这个列表作为对象的 JSON 集合直接保存在实体表中。
当然,除了 JSON 之外,还支持其他格式(例如纯文本或 XML),但根据我的经验,我发现 JSON 最合适。
使用基于文档的存储解决方案
值得一提的是,选择基于文档的数据库技术(例如 MongoDB)还为持久化领域模型实体提供了新选项,因为它允许将聚合保存为整个文档,包括其所有子实体和/或值对象。
【讨论】:
你有两个选择:
对于您的示例,类似:
public class Customer : Entity
{
public Guid CustomerID { get; }
public string LastName { get; set; }
public Address HomeAddress { get; set; }
}
public class Address : ValueObject
{
public string Street { get; set; }
public string City { get; set; }
public string ZipCode { get; set; }
}
选项 1(伪 SQL):
CREATE TABLE Customer (
// aggregate root
customerId int NOT NULL,
lastName VARCHAR(30),
// value object
street VARCHAR(100),
city VARCHAR(50),
zip VARCHAR(10)
CONSTRAINT PK_Customer PRIMARY KEY (customerId)
)
选项 2(伪 SQL):
// aggregate root
CREATE TABLE Customer (
customerId int NOT NULL,
lastName VARCHAR(30)
CONSTRAINT PK_Customer PRIMARY KEY (customerId)
)
// value object
CREATE TABLE Address (
customerId int NOT NULL, // same ID from Customer
street VARCHAR(100),
city VARCHAR(50),
zip VARCHAR(10)
CONSTRAINT PK_Address PRIMARY KEY (customerId)
)
toDomain(sqlResult)函数来转换你的域对象中的查询结果one-table的方式【讨论】:
当 Eric Evans 谈到“实体有身份,值对象没有”时,他不是在谈论数据库中的 ID 列 - 他是在谈论身份作为一个概念。
VO 没有概念身份。这并不意味着他们不应该有 persistence 身份。不要让持久性实现影响您对实体与 VO 的理解。
查看我的帖子here。
【讨论】:
就我对 DDD 的理解而言,值对象只是划分实体的一种方式。如果一个值对象应该在数据库中存储一个 ID,那么它就不是一个值对象。
示例:
领域模型如下所示(C#):
public class Customer : Entity
{
public Guid CustomerID { get; }
public string LastName { get; set; }
public Address HomeAddress { get; set; }
}
public class Address : ValueObject
{
public string Street { get; set; }
public string City { get; set; }
public string ZipCode { get; set; }
}
对应的数据库表看起来像这样(伪 SQL):
CREATE TABLE Customers
(
CustomerID,
LastName,
HomeAddress_Street,
HomeAddress_City,
HomeAddress_ZipCode,
)
要将地址存储在单独的表中,您可以将其设为具有 ID 的实体。
【讨论】:
m not looking for way to completely get rid of it, cause then i wouldnt能够将VO数据存储在另一个表中。
我个人在值对象中有 Id 字段 - 我将其视为值对象的另一个属性(例如名称、位置等)。
它可能不是真正的 DDD,但它对我有用。
【讨论】: