NodeJS使用Prisma如何更新带where条件的多表关联数据
Prisma多表关联更新正确实现方案
原有代码错误点
- 外键赋值逻辑错误:
apprentice表的geId、execution表的reId都是当前表存储的外键字段,仅用来关联字典表,不需要嵌套gender.update/region.update去修改字典表本身的数据,直接给外键字段传对应id值即可完成关联关系更新。 - 一对多关联更新缺少定位条件:
apprentice和execution是一对多关系(一个学徒可对应多条执行记录),原有代码直接写execution.update但未指定要更新的execution记录唯一标识,Prisma无法定位目标记录,会直接抛出语法错误。 - 缺少事务保障:多表分步更新没有加事务,会出现部分表更新成功、部分更新失败的数据不一致问题。
- 参数未做类型转换和空值校验:请求中传递的id类数字参数未做类型转换,日期字段未做空值兼容,容易触发数据库类型报错。
可直接运行的正确代码
app.put("/api/apprentice/:id", async (req, res) => { const apprenticeId = Number(req.params.id) const { apprentice: apprenticeData, execution: executionData, region: reId } = req.body // 基础参数校验 if (!apprenticeData || !executionData || !reId) { return res.status(400).send({ error: "缺少必要请求参数" }) } // 用事务包裹多表更新操作,保证原子性 const updatedResult = await prisma.$transaction(async (tx) => { // 更新apprentice主表基础信息和性别关联 await tx.apprentice.update({ where: { apId: apprenticeId }, data: { geId: Number(apprenticeData.gender), apFirstname: apprenticeData.firstName, apLastname: apprenticeData.lastName, apBirthdate: apprenticeData.birthdate ? new Date(apprenticeData.birthdate) : null, apPhoneNumber: apprenticeData.phoneNumber, } }) // 查询当前学徒关联的目标execution记录,业务上如果是一个学徒仅对应一条执行记录用findFirst即可,如果有多条需要前端传exId指定 const targetExecution = await tx.execution.findFirst({ where: { apId: apprenticeId }, orderBy: { exId: 'desc' } }) if (!targetExecution) { throw new Error("未找到关联的执行记录") } // 更新execution记录内容和关联的地区 await tx.execution.update({ where: { exId: targetExecution.exId }, data: { exDate: new Date(executionData.datetime), exMessage: executionData.message, reId: Number(reId) } }) // 查询并返回带全量关联数据的最终结果 return tx.apprentice.findUnique({ where: { apId: apprenticeId }, include: { gender: true, execution: { include: { region: true } } } }) }) res.send(updatedResult) })
关键规则说明
- 关联更新分两种场景:如果只是修改当前记录和其他表的关联关系,直接给当前表的外键字段赋值即可;如果要同时修改关联表本身存储的内容(比如要改gender表存储的性别名称、region表存储的地区名称),才需要用嵌套
update写法。 - 所有1对多、多对多关系的嵌套更新操作,必须传入目标关联记录的唯一查询条件(一般是主键),否则Prisma无法定位要操作的单条记录。
- 涉及两张及以上表的写操作必须用事务包裹,避免出现脏数据。
- 从请求中获取的数字、日期类型参数必须做类型转换和空值判断,避免触发数据库类型不匹配错误。
内容的提问来源于stack exchange,提问作者Sven Märki
相关产品推荐
相关产品推荐

