返回

Prisma 报错解决:payload 参数必须是对象类型

mysql

搞定 Prisma 中 "TypeError: The 'payload' argument must be of type object. Received null" 错误

在使用 Prisma 操作数据库时,你可能会遇到 "TypeError: The 'payload' argument must be of type object. Received null" 这个错误。别慌,这问题挺常见的,我来帮你分析并解决。

问题

在 Prisma 的使用场景中, 上述错误一般发生于create或者update的操作, 我在向 articles 表插入数据时,碰到了这个错误提示:TypeError: The "payload" argument must be of type object. Received null。其他表的操作都没问题,就这个表不行。

咋回事?

这个错误直接的意思是:Prisma 在创建或更新数据时,期望得到一个对象类型的参数,但实际上却收到了 null

几个可能的原因:

  1. 数据问题 : 传给 Prisma 的 data 参数有问题,可能是个 null,或者里面有些字段的值是 null,而数据库表里这些字段又设置成了非空(NOT NULL)。

  2. Prisma 模式定义 (Schema) 问题 : 你的 schema.prisma 文件里,articles 表的字段定义可能和实际的数据库结构不一致。比如说,schema.prisma 里某个字段允许为空 (没有?标记),但数据库里这个字段却设置了非空约束。

  3. 类型不匹配 : 某个字段被Prisma当做了关系字段, 但实际处理中把它当做了普通字段。

  4. 使用了数据库的保留字或者触发器等等, 导致Prisma的处理逻辑出错。

解决办法

针对上面这些可能的原因,咱一个一个排查:

1. 检查传入的数据

首先,确保传给 prisma.articles.create()data 参数是一个对象,并且里面包含了所有必填字段,而且这些字段的值都不是 null

  • 原理 :Prisma Client 会根据 schema.prisma 里的定义,对传入的数据进行校验。如果数据的格式不对,或者缺少必填字段,就会报错。

  • 操作 : 在你的代码里,用 console.log()body 打印出来看看:

    import prisma from '@/utils/prisma';
    import { NextResponse } from 'next/server';
    
    export async function POST(req: Request) {
      try {
        const body = await req.json();
    
        console.log('收到的请求体:', body); // 看看 body 是啥
    
        if (!body.type || !body.brand || !body.model) {
          return NextResponse.json(
            { error: 'type、brand 和 model 字段都得有!' },
            { status: 400 }
          );
        }
    
        const article = await prisma.articles.create({
          data: {
            ...body,
            dealership_id: 'd9078ca9-4d6e-4d0e-a60d-dabbb3c8e5c2', // 测试用的固定 ID
          },
        });
    
        return NextResponse.json(article, { status: 201 });
      } catch (error) {
        console.error('出错了:', error);
        return NextResponse.json(
          { error: '创建 article 失败了!' },
          { status: 500 }
        );
      }
    }
    

    仔细看看打印出来的 body,是不是少了啥字段,或者哪个字段的值是 null。尤其要看看和articles表定义相关的部分。

2. 核对 Prisma 模式 (Schema)

仔细检查你的 schema.prisma 文件里 articles 表的定义。

  • 原理schema.prisma 是 Prisma 的核心,它定义了数据库表的结构。Prisma Client 会根据这个定义来生成相应的 API,并进行数据校验。

  • 操作

    1. 打开 schema.prisma 文件, 看清楚, 哪些是不允许空的 (没有 ? 修饰)。
    2. 用数据库管理工具(比如 pgAdmin、MySQL Workbench、DBeaver 之类的)连上你的数据库,看看 articles 表的实际结构。
    3. 对比一下,看看 schema.prisma 里的定义和数据库表里的实际结构是不是一致。重点关注字段名、数据类型、是否允许为空 (Nullable) 这些地方。特别注意有默认值的字段和有外键约束的字段。

    如果发现不一致,改 schema.prisma 文件, 然后跑一下 npx prisma migrate dev 来更新数据库。 如果你不确定,可以先跑 npx prisma migrate dev --create-only,这个命令会生成迁移脚本,但不会应用到数据库,你可以先检查一下。

3. 处理可选的关系字段

如果你的 articles 表和其他表有关联,而且这些关联是可选的(比如,一篇文章可以没有作者),就要特别注意。

  • 原理 : 如果 model 存在可选的关系字段, create 操作传入 null 可能导致问题。
  • 操作 : 将可能为 null 的关系设置排除:
        const article = await prisma.articles.create({
          data: {
            type: body.type,
            brand: body.brand,
            model: body.model,
              // ... 其他非关系字段
            dealership_id: 'd9078ca9-4d6e-4d0e-a60d-dabbb3c8e5c2', // 测试用的固定 ID
          },
        });

如果上面的步骤无法确认, 请确认关系字段中, dealership 在数据库中存在且正常。

4. 检查默认值设置

如果 articles表里面有数据库的默认值, 例如created_at设置为了 now(), 请特别留意一下.

  • 原理 : Prisma在某些数据库配置情况下,可能无法很好地与默认值进行交互。

  • 操作 : 在你的create语句里显示赋值,避免触发数据库默认值,例如这样创建时间:

          data: {
            //... 其他字段
            created_at: new Date(), // 显示创建时间
            dealership_id: 'd9078ca9-4d6e-4d0e-a60d-dabbb3c8e5c2',
          },
    

5.数据库保留字和特殊设置

如果你的数据表里面使用到了一些数据库保留字,或者一些特殊的触发器和约束, 也会增加问题排查的难度。

  • 原理 : Prisma 并不完全兼容所有的数据库特性, 对于特别复杂的约束和函数支持可能会出问题。
  • 操作 : 尝试暂时移除复杂的数据库约束、触发器、存储过程。如果这样能解决问题,说明问题的根本原因和数据库的这些特性有关,考虑重构或者用原生 SQL 绕过。

进阶技巧

  • 调试 Prisma Client
    Prisma Client 有个 $on 方法,可以监听它执行的 SQL 查询。你可以用它来观察 Prisma 到底发了什么 SQL 给数据库:

    prisma.$on('query', (e) => {
      console.log('Query:', e.query);
      console.log('Params:', e.params);
      console.log('Duration:', e.duration);
    });
    

从Prisma 角度观察执行SQL, 排查异常。

  • 数据库日志: 开启数据库的日志, 然后从数据库的角度看问题. 对于 PostgreSQL, 可以调整 postgresql.conf 的配置, 然后查看log。
      log_statement = 'all'
    
    记得问题排除之后, 改回去避免日志量太大。

总结一下

解决 "TypeError: The 'payload' argument must be of type object. Received null" 这个错误,主要就是细心。 一步步排查: 数据、Schema 定义, 可选的关系、特殊数据库配置等,总能找到问题所在。