如何在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
相关产品推荐
相关产品推荐

