如何在Prisma与NestJS中同时创建带外键关联的User和Profile实例?
解决Prisma+NestJS中同时创建User和Profile时的外键约束错误
问题原因
你代码里的核心问题是事务内创建Profile时用了全局的this.prismaService,而非事务上下文的tx客户端。
Prisma的$transaction要求事务内的所有数据库操作都必须使用传入的tx实例,这样所有操作才会在同一个事务中执行。你当前的写法中,createUser是在事务里执行的,但createProfile用了全局的prisma实例,这会导致两个操作不在同一个事务中:createUser的提交被事务挂起,此时数据库中还没有这条User记录,createProfile去关联这个userId自然会触发外键约束失败。
修复方案
方案1:改用事务上下文的tx创建Profile
直接修改事务内的Profile创建代码,替换成tx.profile.create:
async createUserAndProfile(body) { const res = await this.prismaService.$transaction(async(tx) => { try { const createUser = await tx.user.create({ data : { loginId : body.loginId, password : body.password } }) // 这里改用tx而不是this.prismaService const createProfile = await tx.profile.create({ data : { firstName : body.firstName, lastName : body.lastName, userId : createUser.id } }) return { createUser, createProfile } } catch(err) { console.log(err); // 抛出错误让事务自动回滚 throw err; } }) return res }
方案2:使用Prisma嵌套创建(更简洁)
利用Prisma的关联嵌套创建能力,一次操作就能同时创建User和关联的Profile,无需手动处理userId:
async createUserAndProfile(body) { try { const result = await this.prismaService.user.create({ data: { loginId: body.loginId, password: body.password, // 直接嵌套创建关联的Profile profile: { create: { firstName: body.firstName, lastName: body.lastName } } }, // 可以选择返回关联的Profile数据 include: { profile: true } }); return result; } catch(err) { console.log(err); throw err; } }
这种写法不仅更简洁,还能确保两个操作在同一个原子事务中执行,避免手动处理事务的繁琐。
额外注意点
- 事务内如果捕获了错误,一定要重新抛出错误,否则Prisma不会自动回滚事务,可能导致数据不一致。
- 你的模型中
Profile.userId设置了@unique(),确保每个User只能对应一个Profile,这个设计是合理的,和当前错误无关。
内容的提问来源于stack exchange,提问作者Nao COMATSU
相关产品推荐
相关产品推荐

