在领域驱动设计中,实体的定义特征之一是它具有身份。
问题:
我无法在创建实例时为实体提供唯一标识。一旦实体持久化(该值由底层数据库提供),此身份仅由存储库提供。
此时我无法开始使用 Guid
值。现有数据使用 int
主键值存储,我无法在实例化时生成唯一的 int。
我的解决方案:
- 每个实体都有一个标识值
- 身份仅在持久化后设置为真实身份(由数据库提供)
- 在持久化之前实例化时将身份设置为默认值
- 如果身份是默认的,则实体可以通过引用进行比较
- 如果标识不是默认的,则实体可以通过标识值进行比较
代码(所有实体的抽象基类):
public abstract class Entity<IdType>
{
private readonly IdType uniqueId;
public IdType Id
{
get
{
return uniqueId;
}
}
public Entity()
{
uniqueId = default(IdType);
}
public Entity(IdType id)
{
if (object.Equals(id, default(IdType)))
{
throw new ArgumentException("The Id of a Domain Model cannot be the default value");
}
uniqueId = id;
}
public override bool Equals(object obj)
{
if (uniqueId.Equals(default(IdType)))
{
var entity = obj as Entity<IdType>;
if (entity != null)
{
return uniqueId.Equals(entity.Id);
}
}
return base.Equals(obj);
}
public override int GetHashCode()
{
return uniqueId.GetHashCode();
}
}
问题:
- 您认为这是在创建实例时生成 Guid 值的一个很好的替代方法吗?
- 是否有更好的解决方案来解决这个问题?
最佳答案
在实例化实体对象时,您可以使用序列生成器生成唯一的 int
/long
标识符。
界面如下:
interface SequenceGenerator {
long getNextSequence();
}
序列生成器的典型实现使用数据库中的序列表。序列表包含两列:sequenceName
和 allocatedSequence
。
当第一次调用 getNextSequence
时,它会向 allocatedSequence
列写入一个大值(例如 100
)并返回 1
。下一次调用将返回 2
而无需访问数据库。当 100
序列用完时,它会再次读取 allocatedSequence
并将其递增 100
。
查看 Hibernate 源代码中的 SequenceHiLoGenerator
。它基本上执行我上面描述的操作。
关于c# - DDD : Entity identity before being persisted,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21250666/