Express与Sequelize:路由POST请求中外键设置问题咨询
解决Sequelize中创建Routine时关联当前用户的问题
你的问题核心是要在创建Routine时正确关联到当前用户,其实有更简洁高效的方式,而且能解决你当前setUser不生效的问题,下面一步步来拆解:
直接在创建时传入外键(推荐方案)
因为你已经配置了Routine.belongsTo(User),Sequelize会自动在routines表中生成userId外键字段。所以不需要额外查询用户再调用setUser,直接在create方法中传入userId即可:
router.post('/', async (req, res, next) => { try { // 注意:这里假设你已经通过认证中间件(比如Passport、JWT)将当前用户信息挂载到了req.user上 // 绝对不要从req.body.user拿用户ID(不安全,恶意用户可篡改) const routine = await Routine.create({ name: req.body.Title, userId: req.user.id // 直接传入当前用户的ID作为外键 }); res.json(routine); } catch (err) { next(err); } });
为什么你原来的代码不生效?
await user.hasOne(routine)完全多余:hasOne是用来定义模型间关联关系的方法,不是用来设置具体实例关联的,这行代码直接删掉就行。- 可能未正确获取到用户实例:如果
req.body.user不存在,或者对应的用户ID在数据库中找不到,User.findOne会返回null,这时候调用setUser(null)自然不会生效。你可以加个判断排查:const user = await User.findOne({ where: { id: req.body.user } }); if (!user) { return res.status(404).json({ message: '目标用户不存在' }); } - 效率冗余:即使原来的代码能生效,也会多一次数据库查询(查询用户),不如直接传入外键高效。
如果你坚持要用setUser方法
如果因为某些场景必须用setUser,修正后的代码如下:
router.post('/', async (req, res, next) => { try { const routine = await Routine.create({ name: req.body.Title }); const user = await User.findOne({ where: { id: req.body.user } }); if (!user) { return res.status(404).json({ message: '目标用户不存在' }); } await routine.setUser(user); // 如果需要返回包含用户信息的routine,可以重新查询一次 const routineWithUser = await Routine.findByPk(routine.id, { include: User }); res.json(routineWithUser); } catch (err) { next(err); } });
最后再强调一次:不要从请求体(req.body)获取用户ID,这是严重的安全隐患,恶意用户可以随意篡改这个值,导致Routine被关联到其他用户。正确的做法是通过认证中间件将当前登录用户的信息挂载到req.user上,然后从req.user.id获取用户ID。
内容的提问来源于stack exchange,提问作者Slaknation
相关产品推荐
相关产品推荐

