如何通过Sequelize在创建用户时填充多对多关联表User_Roles
问题
技术栈:NodeJs、PostgreSQL、Sequelize、Express
我有两个通过User_Roles中间表建立多对多关联的模型(User和Role),roles表中已存在预设角色。现在需要实现:当通过Sequelize的create()方法创建新用户时,利用传入的角色ID数组自动填充User_Roles表,为用户分配对应的角色。
模型代码
const User = sequelize.define('users', { id: { type: DataTypes.INTEGER, autoIncrement: true, primaryKey: true }, email: { type: DataTypes.STRING(320), allowNull: false, unique: true, isEmail: true }, }); const Role = sequelize.define('roles', { id: { type: DataTypes.INTEGER, autoIncrement: true, primaryKey: true }, title: { type: DataTypes.STRING(64), allowNull: false, unique: true }, }); const User_Roles = sequelize.define('user_roles', {}, { timestamps: false }); // 关联配置 User.belongsToMany(Role, { through: User_Roles }); Role.belongsToMany(User, { through: User_Roles });
UserController代码
async create(req, res, next) { const { email, roles } = req.body; if (!email) { return next(ApiError.badRequest('Invalid request')); } if (!Array.isArray(roles) || !roles.length) { return next(ApiError.badRequest('Invalid request')); } const isExistThisEmail = await User.findOne({ where: { email } }); if (isExistThisEmail) { return next(ApiError.badRequest('The email already exists')); } const user = await User.create({ email }); return res.status(201).json(createdUser); }
数据库角色情况
roles表中已存在以下角色记录:
- id: 1, title: admin
- id: 2, title: moderator
- id: 3, title: user
解决方案
方法一:创建用户后调用addRoles批量关联角色
Sequelize会为多对多关联自动生成addRoles(复数形式)方法,可直接用它给用户批量绑定角色:
修改后的UserController代码:
async create(req, res, next) { const { email, roles } = req.body; if (!email) { return next(ApiError.badRequest('请求无效')); } if (!Array.isArray(roles) || !roles.length) { return next(ApiError.badRequest('请求无效')); } // 先校验传入的角色ID是否全部存在,避免无效关联 const existingRoles = await Role.findAll({ where: { id: roles } }); if (existingRoles.length !== roles.length) { return next(ApiError.badRequest('存在无效的角色ID')); } const isExistThisEmail = await User.findOne({ where: { email } }); if (isExistThisEmail) { return next(ApiError.badRequest('该邮箱已存在')); } const user = await User.create({ email }); // 批量添加角色关联 await user.addRoles(roles); // 可选:查询包含角色信息的用户数据返回给前端 const createdUser = await User.findByPk(user.id, { include: [{ model: Role }] }); return res.status(201).json(createdUser); }
方法二:创建用户时直接包含角色关联
可以在User.create()中通过include选项一步完成用户创建与角色绑定,注意需要将角色ID转换为指定格式的对象数组:
async create(req, res, next) { const { email, roles } = req.body; if (!email) { return next(ApiError.badRequest('请求无效')); } if (!Array.isArray(roles) || !roles.length) { return next(ApiError.badRequest('请求无效')); } // 校验角色ID有效性 const existingRoles = await Role.findAll({ where: { id: roles } }); if (existingRoles.length !== roles.length) { return next(ApiError.badRequest('存在无效的角色ID')); } const isExistThisEmail = await User.findOne({ where: { email } }); if (isExistThisEmail) { return next(ApiError.badRequest('该邮箱已存在')); } // 将角色ID转换为Sequelize要求的对象格式 const roleObjects = roles.map(id => ({ id })); // 一步创建用户并关联角色 const createdUser = await User.create( { email, roles: roleObjects }, { include: [{ model: Role }] } ); return res.status(201).json(createdUser); }
额外建议:事务保证原子性
如果需要确保「用户创建」和「角色关联」操作的原子性(要么全部成功,要么全部回滚),可以用Sequelize事务包裹整个流程:
async create(req, res, next) { const { email, roles } = req.body; let transaction; try { transaction = await sequelize.transaction(); // 省略前面的校验逻辑... const user = await User.create({ email }, { transaction }); await user.addRoles(roles, { transaction }); await transaction.commit(); const createdUser = await User.findByPk(user.id, { include: [{ model: Role }] }); return res.status(201).json(createdUser); } catch (error) { if (transaction) await transaction.rollback(); next(ApiError.internal('创建用户失败')); } }
内容的提问来源于stack exchange,提问作者bydyas
相关产品推荐
相关产品推荐

