【问题标题】:Sequelize Mysql - Unable to Insert model with one to many relationshipSequelize Mysql - 无法插入具有一对多关系的模型
【发布时间】:2022-02-07 20:14:06
【问题描述】:

Design Overview: 我有一个包含发票创建和库存管理功能的应用程序。让我们首先了解具有以下 2 个实体的数据库设计:

  1. 发票
  2. 项目

现在,我在这两个实体之间建立了 M:N 关系,因为一张发票可以包含多个项目,而一个项目可以包含在许多此类发票中。

所以,我创建了第三个表,我们称之为连接表来关联这些实体,如下图所示,

Problem Statemet: 我无法使用 include 属性在 子表(invoice_items) 中插入模型。查看下面的代码以了解这里发生了什么错误?

3个模型类如下:

1.发票:

Note: 提供更少的属性以保持简短。

module.exports = (sequelize, DataTypes) => {
    const Invoice = sequelize.define('Invoice', {
        invoiceId: {
            type: DataTypes.INTEGER.UNSIGNED,
            allowNull: false,
            autoIncrement: true,
            primaryKey: true
        },

        invoiceNumber: {
            type: DataTypes.INTEGER(6).UNSIGNED.ZEROFILL,
            allowNull: false,
            unique: true
        }, 

        invoiceTotal: {
            type: DataTypes.DECIMAL(9,2),
            allowNull: false,
            defaultValue: 0.00
        },

        paymentTotal: {
            type: DataTypes.DECIMAL(9,2),
            allowNull: false,
            defaultValue: 0.00
        },

        invoiceDate: {
            type: DataTypes.DATEONLY, 
            defaultValue: DataTypes.NOW,
            allowNull: false
        }

    }, {
        underscored: true
    });

    Invoice.associate = function (model) {
        Invoice.belongsTo(model.Customer, {
            as: 'customer', 
            foreignKey: {
                name: "cust_id",
                allowNull: false
            } 
        });

        // association with 3rd table 
        Invoice.hasMany(model.InvoiceItem, {
            as: 'invoice_item', 
            constraints: true,
            onDelete: 'NO ACTION',
            foreignKey: {
                name: "invoice_id",
                allowNull: false
            }
        });

    };

    return Invoice;
}

2。项目:

Note: 提供更少的属性以保持简短。

module.exports = (sequelize, DataTypes) => {
    const Item = sequelize.define('Item', {
        itemId: {
            type: DataTypes.INTEGER.UNSIGNED,
            allowNull: false,
            autoIncrement: true,
            primaryKey: true
        },

        itemName: {
            type: DataTypes.TEXT,
            allowNull: false,
            defaultValue: ''
        },

        // this is a opening stock
        quantityInStock: {
            type: DataTypes.INTEGER.UNSIGNED,
            allowNull: false,
            defaultValue: 0,
        },

        unitPrice: {
            type: DataTypes.DECIMAL(9,2),
            allowNull: false,
            defaultValue: 0.00
        }

    }, {
        underscored: true 
    });

    Item.associate = function (model) {
        // association with 3rd table 
        Item.hasMany(model.InvoiceItem, {
            as: 'invoice_item', // alias name of a model
            constraints: true,
            onDelete: 'NO ACTION',
            foreignKey: {
                name: "item_id", 
                allowNull: false
            }
        });

    };

    return Item;
}

3。 Invoice_Item:

Note: 提供更少的属性以保持简短。

module.exports = (sequelize, DataTypes) => {
    const InvoiceItem = sequelize.define('InvoiceItem', {
        invoiceItemId: {
            type: DataTypes.INTEGER.UNSIGNED,
            allowNull: false,
            autoIncrement: true,
            primaryKey: true
        },

        quantity: {
            type: DataTypes.INTEGER.UNSIGNED,
            allowNull: false,
            defaultValue: 0,
        },

        rate: {
            type: DataTypes.DECIMAL(9,2),
            allowNull: false,
            defaultValue: 0.00
        }
    }, {
        underscored: true 
    });


    InvoiceItem.associate = function(model) {
        InvoiceItem.belongsTo(model.Invoice,          {
            as: 'invoice', 
            foreignKey: {
                name: "invoice_id",
                allowNull: false
            } 
        });

        InvoiceItem.belongsTo(model.Item, {
             as: 'item',
             foreignKey: {
                name: "item_id",
                allowNull: false
            } 
        });
    }

    return InvoiceItem;
}

现在,我正在使用下面的代码来创建包含项目列表的发票。但是,这不是在连接表中插入子记录(invoice_items)。下面的代码有什么问题?

invoice = await Invoice.create({
                "invoiceNumber": req.body.invoiceNumber,
                "invoiceDate": req.body.invoiceDate,
                "invoiceTotal": req.body.invoiceTotal,
                "paymentTotal": req.body.paymentTotal,
                "cust_id": req.body.customer.custId,
                invoice_items: [{
                    item_id: 1,
                    quantity: 2,
                    rate: 300
                }]
            }, {
                include: [{
                    association: InvoiceItem,
                    as: 'invoice_item'
                }]
            });

【问题讨论】:

  • 您是否尝试将 invoice_item 而非 invoice_items 指定为发票项目数组?
  • 是的,我也试过了,但我收到一个错误消息,TypeError: Cannot read property 'name' of undefined at Function._conformInclude(project_path\node_modules\sequelize\lib\model.js)

标签: mysql node.js sequelize.js


【解决方案1】:

在尝试了这么多变体之后,我了解到我的模型类的关联存在问题。并且,下面是为 M:N(多对多)关系关联 InvoiceItem 模型类的方法。我现在可以更新连接表(invoice_items),方法是为我们在系统中创建的每个发票插入记录,其中包含项目。

Invoice.associate = function (model) {
  // association in Invoice model class
  Invoice.belongsToMany(model.Item, {
    through: 'InvoiceItem',
    constraints: true,
    onDelete: 'NO ACTION',
    foreignKey: {
        name: "invoice_id", // foreign key column name in a table invoice_items table
        allowNull: false
    } 
  });
};

Item.associate = function (model) {
  // association in Item model class
  Item.belongsToMany(model.Invoice, {
    through: 'InvoiceItem',
    constraints: true,
    onDelete: 'NO ACTION',
    foreignKey: {
        name: "item_id", // foreign key column name in a table invoice_items
        allowNull: false
    } 
  });
};

创建包含项目的发票:

Note: 将 itemId (1) 作为参数传递给 addItems() 方法。如果您的发票中有多个项目,那么您可以在此处添加 forEach 循环以迭代每个项目并分别传递 itemIdquantityrate 以获取出售给客户的项目。

// first create the invoice
invoice = await Invoice.create(invoice);

// Next, add record in the join table
await invoice.addItems([1], {
  through: {
      quantity: item.quantity,
      rate: item.rate
  }
});  

具有一个测试结果的数据库表:

1.发票表:

2。 Invoice_items 表(加入表):

【讨论】:

    猜你喜欢
    • 2016-10-15
    • 2019-08-25
    • 1970-01-01
    • 2014-05-16
    • 1970-01-01
    • 2013-11-11
    • 2010-11-13
    • 2013-01-12
    • 1970-01-01
    相关资源
    最近更新 更多