值对象没有标识。 ORM需要标识来更新数据库。
如何欺骗ORM?
(将值对象标记为内部将不起作用,因为ORM位于不同的程序集中并将其移动到同一程序集是不可接受的。)
提前致谢。
答案 0 :(得分:43)
当Eric Evans谈到“实体有身份,Value Objects没有”时,他不是在谈论数据库中的ID列 - 他在谈论身份作为概念。
VO没有概念身份。这并不意味着他们不应该拥有持久性身份。不要让持久性实现让您了解实体与VO。
请参阅我的帖子here。
答案 1 :(得分:5)
就我对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; }
}
相应的数据库表看起来像这样(Pseudo-SQL):
CREATE TABLE Customers
(
CustomerID,
LastName,
HomeAddress_Street,
HomeAddress_City,
HomeAddress_ZipCode,
)
要将地址存储在单独的表中,您可以将其设为具有ID的实体。
答案 2 :(得分:4)
我个人在值对象中有Id字段 - 我将其视为值对象的另一个属性(例如名称,位置等)。
它可能不是真正的DDD,但它适用于我。
答案 3 :(得分:0)
您有2个选择:
以您的示例为例,
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
方法答案 4 :(得分:0)
先前答案中提到的用于持久保存值对象的所有选项-例如将值对象属性展平为它们所属的实体表的列,或者通过为数据模型包括唯一ID将其持久化在单独的表中-有效并得到充分解释。当然,这些选项通常独立于特定的基础数据库技术而适用,这是一个很好的选择。
但是我认为至少值得一提的是 一些其他选项 ,这些选项在许多情况下可能足够且易于实施:
以JSON表示形式存储值对象
这当然取决于您的技术约束,但是如今,许多数据库以及ORM解决方案甚至都提供JSON表示的内置支持。有些甚至包括搜索选项。如果您不希望有太多的项目,您甚至可以通过将该列表作为对象的JSON集合直接保存在实体表中,甚至可以将该方法用于实体内的值对象列表。
除了JSON之外,当然还支持其他格式(例如纯文本或XML),但是根据我的经验,我发现JSON最舒适。
使用基于文档的存储解决方案
也许值得一提的是,选择基于文档的数据库技术(例如 MongoDB )也为持久化域模型实体提供了新的选择。将汇总包含整个文档(包括其所有子实体和/或值对象)持久化。
答案 5 :(得分:0)
VO属于实体。 我们将使用实体的ID(业务ID)来跟踪VO。
VO也可能包含其他实体/ VO,它仅表示OO,封装。 以E-R,1:N为例,我们可以使用联合表对其进行持久化。
关注业务,而不是那些概念。