我正在使用 Typescript 开发 Web 应用程序项目,同时学习和应用 DDD(领域驱动设计)。
在我们的数据库中,我们使用 autoincrement ID's 作为主键。但这种方法在实体持久化之前,ID 不会准备就绪。
在 DDD 中,创建的每个实体,无论在哪里,都应该从一开始就定义其标识符,那么当实体在保存到数据库之前创建时会发生什么? (例如它是在前端创建的)。那么就没有ID了。
在 DDD 中,每个不是实体的值都应该是值对象,因此标识符也应该是值对象。
有了这些前提,我想到了一个 UniqueEntityID 值对象,它将执行以下操作:
这样,每当使用存储库从数据库检索实体时,它都会以 autoincrementId 作为值,但对于新创建的实体,它将使用 UUID。
在保存实体时,如果 ID 未持久化,则会从其属性中删除该 ID,因此会在数据库中创建新实体并生成新 ID。
请告诉我这种方法是否正确,或者它是否是反模式,或者我是否遗漏了某些内容。
这是用于 UniqueEntityID 的代码。
class UniqueEntityID {
private readonly uuid: string
private readonly autoincrementId: number
/**
* Creates an identifier using UUID implementation,
* used when the entity is not yet persisted.
*/
constructor()
/**
* Creates an identifier using the autoincrement ID
* from the database.
* @param id - The ID given from a database autoincrement.
*/
constructor(id: number)
constructor(id?: number) {
if (typeof id === 'undefined') {
this.uuid = v4()
} else {
this.autoincrementId = id
}
}
/**
* Check if the ID is an autoincremented ID generated by
* the database
*/
get isPersisted() {
return typeof this.autoincrementId !== 'undefined'
}
/**
* The value of the ID.
*/
get value() {
return this.autoincrementId ?? this.uuid
}
}
最诚挚的问候, 豪尔赫
请告诉我这种方法是否正确,或者它是否是反模式,或者我是否遗漏了某些内容。
我认为这种花哨的图案的必要性尚不清楚。
关键问题是:数据库中的自动增量列是否适合用作标识符?或者只是数据库的元数据?
例如,在分布式系统中,我们可能需要担心的问题之一是输入消息的重复 - 如果我们收到我们已经处理过的“在数据库中插入新实体”消息的第二个副本,会发生什么?
假设我们不希望数据模型中存在相同信息的多个副本,则需要某种方法来识别该行已经存在的事实。检查标识符是最直接的机制...但是如果您依赖数据库在插入过程中生成标识符,则该检查不可用。
另请参阅:没有人需要可靠的消息传递。
简而言之,您可能最好在任何地方使用 UUID(不一定是随机分配的 UUID,但基于名称的 UUID 可能允许您以可接受的冲突风险确定性地生成标识符)。