You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Express+Sequelize删除关联记录后重现问题求助

问题

在ExpressJS中使用Sequelize执行删除关联记录再创建新记录的操作时,数据库中同时保留了旧记录和新记录。需求是删除所有与quotationId关联的QuotationItem记录,再创建新的关联记录,但多次尝试都没解决问题。相关代码如下:

const Quotation = require('../models/quotation');
const QuotationItem = require('../models/quotation_item');
const Category = require('../models/category');
const Users = require('../models/users');
const Item = require('../models/item');

exports.postEditQuotation = async (req,res,next) => {
    const quotationId = req.body.quotationId;
    const itemsCodes = req.body.code;
    const itemsPicture = req.body.picture;
    const itemsDesc = req.body.desc;
    const itemsUnit = req.body.unit;
    const itemsQty = req.body.quotationQty;
    const itemsTotal = req.body.quotationTotal;
    const quotationDate = req.body.quotationDate;
    const quotationClient = req.body.quotationClient;
    const quotationAttention = req.body.quotationAttention;
    const quotationLocation = req.body.quotationLocation;
    const quotationSubject = req.body.quotationSubject;

    await Quotation.findOne({ where: { id: quotationId } }).then(quotation => {
        quotation.date = quotationDate;
        quotation.client = quotationClient;
        quotation.attention = quotationAttention;
        quotation.location = quotationLocation;
        quotation.subject = quotationSubject;
        quotation.save();
    }).then(async () => {
        await QuotationItem.destroy({
            where: {
                id: quotationId
            }
        }).then(async () => {
            if(Array.isArray(itemsCodes)) {
                for(let i=0; i< itemsCodes.length; i++){
                    await QuotationItem.create({
                        code : itemsCodes[i],
                        picture : itemsPicture[i],
                        desc : itemsDesc[i],
                        unit : itemsUnit[i],
                        qty : itemsQty[i],
                        total : itemsTotal[i],
                        quotationId : quotationId
                    })
                }
            } else {
                await QuotationItem.create({
                    code : itemsCodes,
                    picture : itemsPicture,
                    desc : itemsDesc,
                    unit : itemsUnit,
                    qty : itemsQty,
                    total : itemsTotal,
                    quotationId : quotationId
                })
            }

        })
    }).then(() => {
        res.redirect('/quotations');
    }).catch(err => {
        const error = new Error(err);
        error.httpStatusCode = 500;
        return next(error);
    })
}
解决方案

核心问题排查

  • 删除条件错误:QuotationItem.destroy的where条件写了id: quotationId,但quotationId是关联外键,不是QuotationItem自身的主键id,这导致删除操作根本没匹配到要删除的记录。
  • 异步操作未等待:quotation.save()没有加await,会导致后续的删除、创建操作在主表更新完成前就执行,同时混用await和.then()的嵌套写法也容易导致异步时序混乱。

修复后的代码

const Quotation = require('../models/quotation');
const QuotationItem = require('../models/quotation_item');
const Category = require('../models/category');
const Users = require('../models/users');
const Item = require('../models/item');

exports.postEditQuotation = async (req, res, next) => {
    try {
        const quotationId = req.body.quotationId;
        const itemsCodes = req.body.code;
        const itemsPicture = req.body.picture;
        const itemsDesc = req.body.desc;
        const itemsUnit = req.body.unit;
        const itemsQty = req.body.quotationQty;
        const itemsTotal = req.body.quotationTotal;
        const quotationDate = req.body.quotationDate;
        const quotationClient = req.body.quotationClient;
        const quotationAttention = req.body.quotationAttention;
        const quotationLocation = req.body.quotationLocation;
        const quotationSubject = req.body.quotationSubject;

        // 更新主表Quotation,等待保存完成
        const quotation = await Quotation.findOne({ where: { id: quotationId } });
        quotation.date = quotationDate;
        quotation.client = quotationClient;
        quotation.attention = quotationAttention;
        quotation.location = quotationLocation;
        quotation.subject = quotationSubject;
        await quotation.save();

        // 删除所有关联的QuotationItem,修正where条件为外键quotationId
        await QuotationItem.destroy({
            where: {
                quotationId: quotationId
            }
        });

        // 创建新的关联记录
        if (Array.isArray(itemsCodes)) {
            for (let i = 0; i < itemsCodes.length; i++) {
                await QuotationItem.create({
                    code: itemsCodes[i],
                    picture: itemsPicture[i],
                    desc: itemsDesc[i],
                    unit: itemsUnit[i],
                    qty: itemsQty[i],
                    total: itemsTotal[i],
                    quotationId: quotationId
                });
            }
        } else {
            await QuotationItem.create({
                code: itemsCodes,
                picture: itemsPicture,
                desc: itemsDesc,
                unit: itemsUnit,
                qty: itemsQty,
                total: itemsTotal,
                quotationId: quotationId
            });
        }

        res.redirect('/quotations');
    } catch (err) {
        const error = new Error(err);
        error.httpStatusCode = 500;
        return next(error);
    }
}

额外优化建议

  • 可以开启Sequelize的日志功能,直接查看执行的SQL语句,方便快速验证删除、创建操作是否符合预期。
  • 建议用Sequelize事务包裹整个更新、删除、创建流程,一旦中间步骤出错,所有操作都会回滚,避免出现数据不一致的情况。

内容的提问来源于stack exchange,提问作者othman ali

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.25 04:03:15