DDD 标识符、自增 ID 和 UUID

问题描述 投票:0回答:1

我正在使用 Typescript 开发 Web 应用程序项目,同时学习和应用 DDD(领域驱动设计)。

在我们的数据库中,我们使用 autoincrement ID's 作为主键。但这种方法在实体持久化之前,ID 不会准备就绪。

在 DDD 中,创建的每个实体,无论在哪里,都应该从一开始就定义其标识符,那么当实体在保存到数据库之前创建时会发生什么? (例如它是在前端创建的)。那么就没有ID了。

在 DDD 中,每个不是实体的值都应该是值对象,因此标识符也应该是值对象。

有了这些前提,我想到了一个 UniqueEntityID 值对象,它将执行以下操作:

  • UniqueEntityID 拥有 2 个属性,uuidautoincrementId
  • 创建ID时,如果没有向构造函数传递任何值,它将使用随机生成的uuid,但如果给出了值,则会存储在自增id属性中。
  • 要获取 ID 的实际值,有一个 value getter,它将提供 autoincrementId(如果存在)或 uuid(如果不存在)。

这样,每当使用存储库从数据库检索实体时,它都会以 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
  }
}

最诚挚的问候, 豪尔赫

typescript domain-driven-design
1个回答
0
投票

请告诉我这种方法是否正确,或者它是否是反模式,或者我是否遗漏了某些内容。

我认为这种花哨的图案的必要性尚不清楚。

关键问题是:数据库中的自动增量列是否适合用作标识符?或者只是数据库的元数据?

例如,在分布式系统中,我们可能需要担心的问题之一是输入消息的重复 - 如果我们收到我们已经处理过的“在数据库中插入新实体”消息的第二个副本,会发生什么?

假设我们不希望数据模型中存在相同信息的多个副本,则需要某种方法来识别该行已经存在的事实。检查标识符是最直接的机制...但是如果您依赖数据库在插入过程中生成标识符,则该检查不可用。

另请参阅:没有人需要可靠的消息传递

简而言之,您可能最好在任何地方使用 UUID(不一定是随机分配的 UUID,但基于名称的 UUID 可能允许您以可接受的冲突风险确定性地生成标识符)。

© www.soinside.com 2019 - 2024. All rights reserved.