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

如何用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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.29 20:35:13