Sequelize开启alter执行sync后所有数据表外键被置为null问题求助
问题描述
运行配置了alter: true参数的sequelize sync方法后,数据表中所有外键都被置为null。
调用sync的代码如下:
await sequelize.sync({ alter: true }).then(async (result) => { await initDataUserGroup(); await initDataUserAdmin(); await initDataGateType(); });
包含外键定义的模型示例代码:
const { DataTypes } = require("sequelize"); const { sequelize } = require("../services/DatabaseService"); const UserGroup = require("./UserGroup"); const Biodata = require("./Biodata"); const User = sequelize.define("user", { username: { type: DataTypes.STRING, allowNull: false, unique: true, validate: { notNull: { msg: "Username must not be empty", }, notEmpty: true, }, }, email: { type: DataTypes.STRING, allowNull: false, unique: true, validate: { notNull: true, notEmpty: true, isEmail: true, }, }, password: { type: DataTypes.STRING, allowNull: false, validate: { notNull: true, notEmpty: true, }, }, }); User.UserGroup = User.belongsTo(UserGroup); User.Biodata = User.hasOne(Biodata, { foreignKey: "userId", as: "biodata", }); module.exports = User;
预期表现
配置{ alter: true }参数运行sync后,不应该将所有外键置为null。
实际表现
user表中的userGroupId字段为null,biodata表中的userId字段也为null。
运行环境
- Sequelize版本: ^6.6.5
- Node.js版本: 12.9.1
- 数据库方言: SQLite (SQLite3)
解决方案
该问题是SQLite方言下Sequelize 6.x低版本的已知缺陷:SQLite本身不支持ALTER TABLE修改约束的原生操作,Sequelize处理alter: true时会走「重建表-迁移数据」的流程,6.20.0之前的版本中该流程的外键字段映射逻辑存在问题,导致迁移数据时外键列的值没有被正确复制到新表。
可根据你的场景选择以下任意一种方案解决:
- 升级Sequelize版本:直接将Sequelize升级到6.20.0及以上版本,该版本已经官方修复了SQLite下alter操作外键值丢失的问题。
- 调整sync执行逻辑:如果暂时无法升级版本,可在执行sync前后手动切换外键检查状态,避免重建表时外键值被清空:
// 执行sync前先禁用外键约束 await sequelize.query('PRAGMA foreign_keys = OFF'); await sequelize.sync({ alter: true }); // 执行完sync后重新启用外键约束 await sequelize.query('PRAGMA foreign_keys = ON'); // 再执行数据初始化逻辑 await initDataUserGroup(); await initDataUserAdmin(); await initDataGateType();
- 显式声明外键字段:在模型定义中手动写出所有外键字段的属性,避免Sequelize自动生成字段时判定为需要变更,进而触发重建表操作:
// User模型中补充外键字段定义 const User = sequelize.define("user", { // 原有username、email、password字段定义不变 userGroupId: { type: DataTypes.INTEGER, references: { model: UserGroup, key: 'id' } } });
- 开发环境用force模式替代:如果是本地开发场景,可将
alter: true改为force: true,每次启动时重建全表后重新插入初始化数据,不会出现外键丢失问题。
内容的提问来源于stack exchange,提问作者Lukas Fam
相关产品推荐
相关产品推荐

