如何用Prisma自动将Int类型ID转为哈希字符串?遇报错求助
问题:如何通过Prisma自动将Int类型ID转为哈希字符串并解决查询验证错误
我使用Postgres + Prisma ORM,拥有多个带关联字段的模型,想找一种非取巧的方法,在将数据返回给用户前对所有ID进行哈希处理,但查阅文档后未找到能覆盖所有场景的方案。尝试了Jordan的扩展方案,代码如下:
const getPrismaClient = () => { const client = new PrismaClient(); client.$extends({ result: { blog: { // 创建虚拟的hashedId字段 hashedId: { needs: { id: true }, compute(client) { return intToHashedString(client.id); }, }, }, }, }); client.blog .findMany({ select: { hashedId: true }, }) .then((r) => { console.log(r); }); return client; };
运行时出现以下错误:
error - unhandledRejection: PrismaClientValidationError: Invalid `prisma.blog.findMany()` invocation: { select: { hashedId: true, ~~~~~~~~ ? id?: true, ? title?: true, ? slug?: true, ? image?: true, ? description?: true, ? views?: true, ? authorId?: true, clientVersion: '4.11.0' }
错误原因
Prisma通过$extends创建的hashedId是虚拟计算字段,不属于模型schema中定义的原生字段,直接在select里指定会触发验证错误——Prisma的查询校验只识别原生字段。另外,你用了原始的client执行查询,而非$extends返回的扩展客户端实例,这也会导致扩展逻辑不生效。
解决方案
1. 修正基础查询逻辑
因为hashedId的计算依赖原生id字段,查询时必须先选中id,同时要用扩展后的客户端执行查询:
const getPrismaClient = () => { const client = new PrismaClient(); // 保存扩展后的客户端实例 const extendedClient = client.$extends({ result: { blog: { hashedId: { needs: { id: true }, compute(blog) { // 参数名改为blog更清晰,避免和client混淆 return intToHashedString(blog.id); }, }, }, }, }); // 关键:select中包含依赖的id字段,用扩展客户端查询 extendedClient.blog .findMany({ select: { id: true, title: true }, // 按需选择其他原生字段,必须包含id }) .then((r) => { // 返回的每个对象会自动带上hashedId console.log(r); }); return extendedClient; };
2. 批量给所有模型添加哈希ID(进阶)
如果要给所有带id字段的模型都自动生成hashedId,可以批量遍历模型配置,不用逐个编写:
const getPrismaClient = () => { const client = new PrismaClient(); const resultExtensions = {}; // 遍历所有模型(排除Prisma内置方法) Object.keys(client).forEach(modelName => { if (!['$extends', '$connect', '$disconnect', '$queryRaw', '$executeRaw'].includes(modelName)) { resultExtensions[modelName] = { hashedId: { needs: { id: true }, compute(model) { return intToHashedString(model.id); }, }, }; } }); const extendedClient = client.$extends({ result: resultExtensions, }); // 示例:查询用户模型也会自动带上hashedId extendedClient.user.findUnique({ where: { id: 1 } }) .then(user => console.log(user.hashedId)); return extendedClient; };
3. 隐藏原生ID返回给用户(可选)
如果不想把原生id暴露给用户,查询后可以手动剔除:
extendedClient.blog.findMany({ select: { id: true, title: true } }) .then(blogs => blogs.map(blog => { // 解构去掉原生id,保留hashedId和其他字段 const { id, ...rest } = blog; return { ...rest, hashedId: blog.hashedId }; }));
内容的提问来源于stack exchange,提问作者YaDev
相关产品推荐
相关产品推荐

