Next.js结合Prisma更新用户多对多角色返回空数组问题咨询
问题原因
你遇到的接口返回角色为空的直接原因有两个:
updateUserRoles函数中,使用map遍历角色数组创建关联记录时,没有等待所有异步创建操作完成就结束了函数执行。async函数包裹的map会返回Promise数组,你没有用Promise.all包装等待所有Promise执行结束,导致await updateUserRoles(id, roles)实际上在删除旧角色后就立即返回了,后续查询用户数据时新角色还没插入到数据库。- 你的Schema存在设计错误:
customer_role表的role_id字段单独加了@unique约束,这会导致同一个角色只能分配给一个用户,完全不符合多对多的设计需求,后续分配角色时一定会触发唯一约束报错。
修复方案
1. 快速修复现有异步问题
修改updateUserRoles函数,等待所有角色创建操作完成:
const updateUserRoles = async (userID: string, roles: { id: string }[]) => { try { await prisma.customer_role.deleteMany({ where: { customer_id: userID }, }); // 等待所有创建请求执行完成再结束函数 await Promise.all( roles.map((role: { id: string }) => prisma.customer_role.create({ data: { customer_id: userID, role_id: role.id, }, }) ) ); } catch (error) { throw new Error(error as string); } };
2. 修复Schema约束错误
修改customer_role模型,删除role_id的单独唯一约束,新增用户+角色的联合唯一约束:
model customer_role { id String @id @default(uuid()) @db.Uuid customer_id String @db.Uuid role_id String @db.Uuid // 删除原来的@unique customer customer @relation(fields: [customer_id], references: [id], onDelete: Cascade) role role @relation(fields: [role_id], references: [id]) @@unique([customer_id, role_id]) // 新增:同一个用户不能重复绑定同一个角色 }
多对多角色更新的最优实现
方案1:嵌套操作+原子更新(推荐绝大多数场景使用)
不需要拆分多次数据库请求,直接在一次update操作中完成用户信息更新、角色更新、返回最新数据三个逻辑,Prisma自动做事务处理,保证数据一致性:
const updateUser = async (req: NextApiRequest, res: NextApiResponse) => { const { query: { id }, body: { name, email, roles }, } = req as { query: { [key: string]: string }; body: any }; try { const updatedUser = await prisma.customer.update({ where: { id }, data: { name, email, // 嵌套更新关联角色 customer_roles: { // 删除当前用户所有旧角色关联 deleteMany: {}, // 批量插入新的角色关联 createMany: { data: roles.map((role: {id: string}) => ({ role_id: role.id })) } } }, // 直接返回带角色信息的最新用户数据,不需要额外查询 include: { customer_roles: { select: { role: { select: { id: true, name: true } } } } } }); res.status(200).json(updatedUser); } catch (error) { res.status(400).json((error as Error).message); } };
这个方案的优势是代码简洁、性能更好、天然支持原子性,不会出现用户信息更新成功但角色更新失败的脏数据问题。
方案2:增量更新(适合角色数量多的场景)
如果单用户可分配的角色数量很多,先删后加会产生不必要的数据库操作,可以对比新旧角色的差异,只做增量更新:
const updateUserRoles = async (userID: string, newRoles: {id: string}[]) => { // 查询用户当前已有角色 const currentRoles = await prisma.customer_role.findMany({ where: { customer_id: userID }, select: { role_id: true } }); const currentRoleIds = currentRoles.map(r => r.role_id); const newRoleIds = newRoles.map(r => r.id); // 计算要删除和要新增的角色 const toDelete = currentRoleIds.filter(id => !newRoleIds.includes(id)); const toAdd = newRoleIds.filter(id => !currentRoleIds.includes(id)); // 用事务保证两个操作原子性 await prisma.$transaction([ prisma.customer_role.deleteMany({ where: { customer_id: userID, role_id: { in: toDelete } } }), prisma.customer_role.createMany({ data: toAdd.map(roleId => ({ customer_id: userID, role_id: roleId })) }) ]); };
内容的提问来源于stack exchange,提问作者Mike4610
相关产品推荐
相关产品推荐

