Sequelize配置一对一关联后插入外键数据报SQLITE外键约束错误
问题原因及解决方案
核心错误原因
- 订单插入操作未等待完成就执行到期记录插入
你写的Order.bulkCreate是异步返回Promise的操作,但在addOrders方法中调用后没有加await就直接resolve,导致await addOrders()执行结束时,订单数据实际还没入库。此时执行addExpiries插入外键OrderId时,找不到对应的订单主键,触发外键约束报错。 - 到期记录插入的异步逻辑存在未等待完成的问题
addExpiries里每个Expiry.create都是异步操作,你没有收集所有Promise并等待全部完成就resolve,会导致后续逻辑无法感知插入何时真正结束。 - 类型不匹配隐患
csv-parser读取的所有字段默认都是字符串类型,你直接把字符串类型的row.order_id赋值给整型的主键/外键字段,极端情况下会因为类型不匹配触发外键校验失败。
修复代码修改点
1. 修正addOrders的异步逻辑
function addOrders() { return new Promise(async (resolve) => { const data = [] fs.createReadStream('SUP_orders.csv').pipe(csv()).on('data', (row) => { let orderDate = moment(row.order_date).format('YYYY-MM-DD') data.push({ id: parseInt(row.order_id), // 显式转为整型 merchantId: parseInt(row.merchant_id), merchantName: row.merchant_name, orderAmt: parseInt(row.order_amount), orderDate: orderDate, expiryDate: moment(orderDate).add(19, 'days') }) }).on('end', async () => { await Order.bulkCreate(data, { // 等待批量插入完成再resolve validate: true }) resolve() }) }) }
2. 修正addExpiries的异步逻辑
function addExpiries() { return new Promise((resolve) => { const tasks = [] // 收集所有插入任务 fs.createReadStream('SUP_expiries.csv').pipe(csv()).on('data', (row) => { tasks.push(Expiry.create({ merchantId: parseInt(row.merchant_id), OrderId: parseInt(row.order_id), // 显式转为整型 expiredDate: moment(row.expire_date).format('YYYY-MM-DD'), expiredAmt: parseInt(row.expired_sum) })) }).on('end', async () => { await Promise.all(tasks) // 等待所有插入任务完成再resolve resolve() }) }) }
3. 可选:显式关闭Order主键的自增属性
避免Sequelize自动生成的自增逻辑和你手动传入的id冲突:
const Order = sequelize.define('Order', { id: { type: DataTypes.INTEGER, primaryKey: true, autoIncrement: false // 新增该行 }, // 其余字段保持不变 }, { tableName: 'SUP_orders' })
额外排查方向
如果修改后仍报错,可以在插入Expiry前打印row.order_id,去Orders表中确认该id是否真实存在,排除CSV数据本身存在无效订单id的问题。
内容的提问来源于stack exchange,提问作者Matty
相关产品推荐
相关产品推荐

