You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Prisma中实现返回类型化对象的通用ID系统?

通过通用CUID查询图片/视频记录的数据库配置方案

场景说明

现有images和videos两张数据库表,二者均使用CUID作为主键。需求是通过一个通用ID(例如cld7q83rc000008mfc3pq5q6a)查询该ID对应的记录属于图片还是视频,且需要保留类型信息,示例业务代码如下:

function findAny (cuid: string) {
  const universal = await prisma.universal.findUnique({
    where: {
      id: 'cld7q83rc000008mfc3pq5q6a',
    },
  })

  if (universal.image) {
     return {...universal.image, extraImageInfo: true }
  } else {
     return getTypeFromUniversalFind(universal)
  }
}

可选方案汇总

目前有四种可选配置思路:

  • 非关系型「通用键」表:包含id、table_name、item_id字段
  • 关系型「通用键」表:包含id、image_id、video_id等字段
  • 动态生成关联视图(VIEW)
  • 直接关联所有表进行查询

补充两种具体方案的Prisma模型

方案1:非关系型通用键表

该方案的通用键表仅记录类型标识和关联ID,不建立数据库层面的关联约束:

model Image {
  uuid String @db.Uuid @default(uuid()) @unique
  src String
}

model Video {
  uuid String @db.Uuid @default(uuid()) @unique
  src String
}

model UniversalKey {
  uuid String @db.Uuid @default(uuid()) @unique
  table String # 存储"image"或"video"标识类型
  itemUuid String # 关联的图片/视频ID,无数据库级关系绑定
}

方案2:关系型通用键表

该方案通过数据库外键建立通用键与图片、视频表的关联,每个类型对应一个可选字段:

model Image {
  uuid String @db.Uuid @default(uuid()) @unique
  src String
  universalKey UniversalKey?
}

model Video {
  uuid String @db.Uuid @default(uuid()) @unique
  src String
  universalKey UniversalKey?
}

model UniversalKey {
  uuid String @db.Uuid @default(uuid()) @unique
  image Image? @relation(fields: [imageId], references: [uuid])
  imageId String? @unique
  video Video? @relation(fields: [videoId], references: [uuid])
  videoId String? @unique
  # 新增类型时需要添加对应字段和关联配置
}

方案分析与推荐

方案1(非关系型通用键表)

  • 优势:扩展性强,新增类型时仅需修改业务代码,无需变更表结构;表结构简单,写入性能高。
  • 劣势:数据库层面无关联约束,可能出现itemUuid无效的脏数据;查询时需先查通用键表获取类型,再二次查询对应表,多一次数据库请求。
  • 适配场景:类型频繁新增、对数据一致性要求不极端,或愿意在业务层处理数据校验的场景。

方案2(关系型通用键表)

  • 优势:数据库层面通过外键保证数据一致性,不会出现无效关联;查询时可通过Prisma的include直接关联查询出对应记录,无需二次请求,完全匹配你给出的示例代码逻辑。
  • 劣势:扩展性差,新增类型时必须修改UniversalKey表结构,添加对应关联字段;表结构会随类型增多变得臃肿。
  • 适配场景:类型相对固定、对数据一致性要求高,且希望通过ORM直接关联查询的场景。

方案3(动态视图)

  • 思路:创建一个视图,将images和videos的字段合并,同时添加type标识字段(如'image'/'video')。
  • 优势:查询时直接查视图即可获取类型和数据,无需额外关联;无需维护额外的通用键表。
  • 劣势:视图是虚拟表,无法直接通过视图更新数据;新增类型时需要修改视图定义;如果两张表字段差异大,视图字段会有大量NULL值。

方案4(关联所有表查询)

  • 思路:直接通过通用ID同时查询images和videos表,判断哪个表有结果。
  • 优势:无需额外维护任何表或视图,实现简单。
  • 劣势:每次查询都会发起多个数据库请求(或一个联合查询),性能随类型增多而下降;业务层需要处理多表查询的结果判断逻辑。

结合你提供的示例代码逻辑,方案2(关系型通用键表)是最贴合需求的选择,它能直接通过ORM关联查询返回包含类型信息的结果。如果未来类型新增频繁,也可以考虑方案1,但需要在业务层处理二次查询和数据校验。

内容的提问来源于stack exchange,提问作者ThomasReggi

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.04 01:40:23