使用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
相关产品推荐
相关产品推荐

