使用Sequelize的autoIncrementIdentity插种子数据报非空约束错误
问题:使用
autoIncrementIdentity时批量插入种子数据触发非空约束错误 问题背景
创建project表的迁移文件时,将id字段设为INTEGER类型主键并开启autoIncrementIdentity,但执行种子文件批量插入时触发非空约束错误,报错显示id字段为null。改为autoIncrement: true则插入正常,需要解决使用autoIncrementIdentity时的种子数据插入问题。
环境信息
- psql版本17(Docker镜像)
- Sequelize版本6.37.5
- DBeaver版本24.3.1
错误详情
ERROR: null value in column "id" of relation "projects" violates not-null constraint
ERROR DETAIL: Failing row contains (null, {"theme": "light", "layout": "grid"}, Project Alpha, 2024-12-25 05:56:28.86+00, 2024-12-25 05:56:28.86+00).
相关代码
种子文件
const convertToString = (attributes) => `${JSON.stringify(attributes)}`; // Seed projects and get the inserted IDs await queryInterface.bulkInsert( "projects", [ { attributes: convertToString({ layout: "grid", theme: "light" }), name: "Project Alpha", createdAt: new Date(), updatedAt: new Date(), }, { attributes: convertToString({ layout: "flex", theme: "dark" }), name: "Project Beta", createdAt: new Date(), updatedAt: new Date(), }, ], { returning: true } );
迁移文件
await queryInterface.createTable("projects", { id: { primaryKey: true, type: Sequelize.INTEGER, autoIncrementIdentity: true, }, attributes: { type: Sequelize.JSONB, allowNull: true, }, name: { type: Sequelize.STRING(64), allowNull: false, }, createdAt: { allowNull: false, type: Sequelize.DATE, defaultValue: Sequelize.literal("CURRENT_TIMESTAMP"), }, updatedAt: { allowNull: false, type: Sequelize.DATE, defaultValue: Sequelize.literal("CURRENT_TIMESTAMP"), onUpdate: Sequelize.literal("CURRENT_TIMESTAMP"), // Automatically updates on modification }, });
解决方案
问题核心是autoIncrementIdentity与autoIncrement的行为差异:
autoIncrement: true会同时配置PostgreSQL的序列和标识列,Sequelize在批量插入时会自动忽略id字段,由数据库生成值。autoIncrementIdentity: true仅创建PostgreSQL 10+支持的标识列,但Sequelize的bulkInsert默认不会自动处理标识列的自动生成逻辑,导致插入时传递null值触发约束错误。
方法1:在批量插入时显式指定id为默认值
修改种子文件,在每个插入对象中添加id: Sequelize.literal('DEFAULT'),让数据库使用标识列的自动生成规则:
const convertToString = (attributes) => `${JSON.stringify(attributes)}`; await queryInterface.bulkInsert( "projects", [ { id: Sequelize.literal('DEFAULT'), attributes: convertToString({ layout: "grid", theme: "light" }), name: "Project Alpha", createdAt: new Date(), updatedAt: new Date(), }, { id: Sequelize.literal('DEFAULT'), attributes: convertToString({ layout: "flex", theme: "dark" }), name: "Project Beta", createdAt: new Date(), updatedAt: new Date(), }, ], { returning: true } );
方法2:显式配置标识列生成策略
修改迁移文件,在id字段配置中添加identity参数,明确标识列的生成策略,让Sequelize识别该字段为自动生成的标识列:
await queryInterface.createTable("projects", { id: { primaryKey: true, type: Sequelize.INTEGER, autoIncrementIdentity: true, identity: 'by default' // 可选值:'by default'(允许手动指定id)或'always'(强制数据库生成) }, // 其他字段配置保持不变 });
Sequelize 6.37.5已支持该配置,修改后bulkInsert会自动处理id字段的生成,无需手动添加默认值。
内容的提问来源于stack exchange,提问作者levantiler
相关产品推荐
相关产品推荐

