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

使用Prisma upsert更新/创建通知表时的问题排查

问题:Prisma模型关联与Upsert操作异常处理

1. 模型定义与关联疑问

我在prisma.schema中定义了Notifications模型:

model Notifications {
  id            String           @id @default(cuid())
  userId        String           //@unique ???? 是否需要添加这个属性
  type          NotificationType @default(none)
  mobile        Boolean
  communication Boolean
  social        Boolean
  marketing     Boolean
  security      Boolean
  user          User             @relation(fields: [userId], references: [id], onDelete: Cascade)
}

同时User模型定义如下:

model User {
  id            String          @id @default(cuid())
  name          String?
  accounts      Account[]
  notifications Notifications[]
}

想确认两个模型的关联是否正确,以及userId字段是否需要添加@unique约束。

2. Upsert操作的需求与初始问题

我需要实现:用户的通知记录不存在则创建,存在则更新,传入的id来自用户session数据。

表单调用代码:

const update = await updateNotifications(
  session.user.id,
  data.type,
  data.communication_emails,
  data.marketing_emails,
  data.social_emails,
  data.security_emails,
  data.mobile,
);

最初的服务端代码:

async function updateNotifications(
  id: string,
  type: NotificationType,
  communication: boolean,
  marketing: boolean,
  social: boolean,
  security: boolean,
  mobile: boolean,
) {
  "use server";
  try {
    await prisma.notifications.upsert({
      where: { id },
      update: {
        type,
        communication,
        marketing,
        social,
        security,
        mobile,
      },
      create: {
        id,
        userId,
        type,
        communication,
        marketing,
        social,
        security,
        mobile,
      },
    });
    return upsertNotifications;
  } catch (error) {
    console.error("Error updating user: ", error);
  }
}

这里遇到了userId无值的问题,同时疑惑userId是否需要加@unique,以及如何在upsert中正确传递它。

3. 更新后的新问题

修改后能成功创建记录,但每次都会生成新的notification对象,无法更新已有记录,修改后的代码:

async function updateNotifications(
  id: string,
  type: NotificationType,
  communication: boolean,
  marketing: boolean,
  social: boolean,
  security: boolean,
  mobile: boolean,
) {
  "use server";
  try {
    const update = await prisma.notifications.upsert({
      where: { id },
      update: {
        type,
        communication,
        marketing,
        social,
        security,
        mobile,
      },
      create: {
        userId: id,
        type,
        communication,
        marketing,
        social,
        security,
        mobile,
      },
    });
}

问题解决方法

核心原因

当前upsert的where条件用的是Notifications模型的id,但传入的id是用户的ID(session.user.id),而Notifications的id是自动生成的cuid,两者完全不匹配,导致每次都找不到已有记录,触发创建逻辑。

步骤1:给userId添加@unique约束

一个用户应该只有一条通知配置记录,必须给userId加唯一约束,同时确保模型关联逻辑正确:

model Notifications {
  id            String           @id @default(cuid())
  userId        String           @unique // 必须添加,确保单用户单记录
  type          NotificationType @default(none)
  mobile        Boolean
  communication Boolean
  social        Boolean
  marketing     Boolean
  security      Boolean
  user          User             @relation(fields: [userId], references: [id], onDelete: Cascade)
}

修改后运行prisma migrate dev更新数据库结构。

步骤2:修改upsert的匹配条件

把where条件从id改成userId,用用户ID匹配对应的通知记录:

async function updateNotifications(
  userId: string, // 参数名改为userId更清晰
  type: NotificationType,
  communication: boolean,
  marketing: boolean,
  social: boolean,
  security: boolean,
  mobile: boolean,
) {
  "use server";
  try {
    const result = await prisma.notifications.upsert({
      where: { userId }, // 用用户ID匹配记录
      update: {
        type,
        communication,
        marketing,
        social,
        security,
        mobile,
      },
      create: {
        userId,
        type,
        communication,
        marketing,
        social,
        security,
        mobile,
      },
    });
    return result;
  } catch (error) {
    console.error("更新通知设置失败: ", error);
  }
}

步骤3:表单调用保持不变

原来的调用传入session.user.id是正确的,因为现在参数接收的就是用户ID:

const update = await updateNotifications(
  session.user.id,
  data.type,
  data.communication_emails,
  data.marketing_emails,
  data.social_emails,
  data.security_emails,
  data.mobile,
);

补充说明

  • 添加@unique不仅能保证业务逻辑(单用户单记录),还能让数据库生成唯一索引,提升查询效率,同时防止重复创建记录。
  • 之前的错误本质是混淆了Notifications模型的ID和用户ID两个不同的字段,导致匹配逻辑完全错误。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.21 02:15:53