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

Prisma查询返回null?房屋删除接口校验失败求助

Prisma查询findFirst返回null的排查与解决

先看你的代码和问题:

import { prisma } from "../../../database/prismaClient"

interface IDeleteHouseRequest {
    id: string
    tenantId: string
}

export class DeleteHouseUseCase {
    async execute({ id, tenantId }: IDeleteHouseRequest) {
        const findHouse = await prisma.house.findFirst({
            where: {
                id: id,
                tenantId: tenantId
            },
        })

        if (!findHouse) {
            throw new Error("It was not possible to delete this house.")
        }

        const deletedHouse = await prisma.house.delete({
            where: {
                id: id
            }
        })

        return deletedHouse
    }
}

问题描述:代码卡在该校验环节,已确认传入的id和tenantId参数正确,数据库中存在对应房屋数据,但findHouse查询结果为null,无法通过此校验。

下面是几个大概率的排查方向和解决方案:

1. 数据类型/格式不匹配

最常见的原因是传入参数的类型/格式和数据库存储的不一致:

  • 比如数据库中id是UUID类型,你传入的字符串大小写和库中不一致(部分数据库对UUID大小写敏感);
  • 或者tenantId在Prisma Schema中定义为Int,但你传入的是字符串格式的数字;
  • 也可能是参数包含隐形空格,比如传入的tenantId末尾多了空格。

解决:

  • 打开schema.prisma检查House模型的字段类型:
    model House {
      id        String   @id @default(uuid())
      tenantId  String   // 确认这里的类型和传入参数一致
      // 其他字段
    }
    
  • 在查询前打印参数的原始值和类型,和数据库中存储的内容精确比对:
    console.log("传入的id:", id, "类型:", typeof id)
    console.log("传入的tenantId:", tenantId, "类型:", typeof tenantId)
    

2. 全局中间件/软删除逻辑干扰

如果你的Prisma客户端初始化时加了全局中间件,比如软删除过滤,会导致查询自动加上额外条件,过滤掉你要找的数据:

// 示例:全局软删除中间件
prisma.$use(async (params, next) => {
  if (params.model === 'House') {
    params.args.where = { ...params.args.where, isDeleted: false }
  }
  return next(params)
})

如果数据库中的目标数据isDeleted字段为true,findFirst就查不到。

解决:检查Prisma客户端的初始化代码,有没有类似的全局过滤逻辑;如果是软删除场景,查询时需要显式加上isDeleted: false(或对应状态)。

3. 数据库环境不匹配

你可能犯了低级错误:代码连接的数据库和你查看数据的数据库不是同一个(比如代码连测试库,你看的是生产库)。

解决:确认prisma/.env中的DATABASE_URL指向的数据库,和你用来验证数据存在的数据库是同一个;可以直接在数据库中执行原生SQL查询,验证参数是否能查到数据:

SELECT * FROM House WHERE id = '你的id' AND tenantId = '你的tenantId';

4. 优化方案:合并校验与删除操作

其实你不需要先查询再删除,Prisma的delete操作本身可以同时校验多个条件,而且更高效(减少一次数据库请求),还能避免查询后到删除前的数据变更问题:

import { prisma } from "../../../database/prismaClient"
import { PrismaClientKnownRequestError } from '@prisma/client/runtime/library'

interface IDeleteHouseRequest {
    id: string
    tenantId: string
}

export class DeleteHouseUseCase {
    async execute({ id, tenantId }: IDeleteHouseRequest) {
        try {
            const deletedHouse = await prisma.house.delete({
                where: {
                    id: id,
                    tenantId: tenantId // 同时校验id和tenantId
                }
            })
            return deletedHouse
        } catch (error) {
            // 捕获Prisma的"找不到记录"错误
            if (error instanceof PrismaClientKnownRequestError && error.code === 'P2025') {
                throw new Error("It was not possible to delete this house.")
            }
            // 抛出其他未知错误
            throw error
        }
    }
}

当找不到符合id和tenantId的记录时,Prisma会抛出P2025错误,直接捕获这个错误即可完成校验逻辑。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.31 02:36:30