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

如何在Prisma中通过外键更新实体?Express场景问题解决

问题:Prisma更新视频时无法使用creatorId作为查询条件

我开发了一个简单API,允许已认证用户对视频执行CRUD操作。Video模型包含名为creatorId的外键,关联创建该视频的User模型。尝试将creatorId传入Prisma函数的where子句更新视频时,出现如下错误:

Unknown arg `creatorId` in where.creatorId for type VideoWhereUniqueInput. Available args:

type VideoWhereUniqueInput {
  id?: Int
}

我的Express JS实现代码

export const updateVideo = async (req, res, next) => {

    const userId = parseInt(req.user.id)
    const videoId = parseInt(req.params.id)

    try {

        // 检查视频是否存在
        const videoToUpdate = await prisma.video.findUnique({
            where: {
                id: videoId
            }
        })

        // 视频不存在则抛出错误
        if (!videoToUpdate)
            return next(createError(404, `ID为${req.params.id}的视频不存在`))

        // 更新视频
        const updatedVideo = await prisma.video.update({

            // 尝试定位用户创建的视频
            where: {
                creatorId: userId
            },

            // 要修改的数据
            data: {
                ...req.body,
            }
        })

        res.status(200).json(updatedVideo)
    } 

    catch (error) {
        console.log(error)
        next(error)
    }
}

Prisma模型定义

model User {
  id Int @id @default(autoincrement())
  email String @unique 
  name String
  password String
  img String?
  subscriberCount Int? @default(0)
  videos Video[]
  comments Comment[]
  followedBy Follows[] @relation("following")
  following Follows[] @relation("follower")
  likedVideos Likes[]
}

model Video {
  id Int @id @default(autoincrement())
  creator User @relation(fields: [creatorId], references: [id])
  creatorId Int 
  title String 
  description String 
  videoUrl String?
  views Int? @default(0)
  tag String? @default("Uncategorized")
  likedBy Likes[]
  comments Comment[]
}

我想知道如何修复该问题,使Prisma能够基于外键执行更新查询?另外我好奇为何这种简单方案无效,比如为何主键可以这么用而外键不行?


修复方案

问题出在prisma.video.update的where条件上:你需要同时指定id和creatorId来定位唯一且属于当前用户的视频,而且要给Video模型添加id+creatorId的复合唯一约束,这样Prisma才会把这组字段识别为有效的唯一查询条件。

步骤1:修改Prisma模型,添加复合唯一约束

在Video模型中给id和creatorId添加@@unique约束:

model Video {
  id Int @id @default(autoincrement())
  creator User @relation(fields: [creatorId], references: [id])
  creatorId Int 
  title String 
  description String 
  videoUrl String?
  views Int? @default(0)
  tag String? @default("Uncategorized")
  likedBy Likes[]
  comments Comment[]

  // 添加复合唯一约束
  @@unique([id, creatorId])
}

然后运行npx prisma migrate dev应用这个变更。

步骤2:修改updateVideo函数的where条件

现在可以同时用id和creatorId作为查询条件,既确保更新的是指定ID的视频,又验证该视频属于当前用户:

export const updateVideo = async (req, res, next) => {

    const userId = parseInt(req.user.id)
    const videoId = parseInt(req.params.id)

    try {
        // 直接用复合条件更新,同时验证视频存在且属于当前用户
        const updatedVideo = await prisma.video.update({
            where: {
                id_creatorId: { // Prisma自动生成的复合字段名:id+下划线+creatorId
                    id: videoId,
                    creatorId: userId
                }
            },
            data: {
                ...req.body,
            }
        })

        res.status(200).json(updatedVideo)
    } catch (error) {
        // 处理视频不存在或无权限的情况
        if (error.code === 'P2025') {
            return next(createError(404, `视频不存在或您无权限修改`))
        }
        console.log(error)
        next(error)
    }
}

这样修改后,既实现了权限验证(只有视频创作者能修改),又符合Prisma的查询规则。


为什么直接用creatorId不行?

Prisma的update、delete这类操作要求where子句必须传入唯一标识(即VideoWhereUniqueInput类型),目的是确保只会操作一条数据:

  • 主键id天生是唯一的,所以可以单独用来定位一条视频;
  • 而creatorId只是外键,一个用户可以创建多个视频,单独用它无法定位到唯一的视频,不符合VideoWhereUniqueInput的要求,因此Prisma不允许这么用。

只有当某个字段(或字段组合)被标记为unique时,Prisma才会把它加入到WhereUniqueInput的可用参数中,这就是为什么添加复合唯一约束后就能用id+creatorId作为查询条件的原因。


内容的提问来源于stack exchange,提问作者kimetsu no yaiba

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.22 22:30:57