[英]Sequelize Mysql - Unable to Insert model with one to many relationship
Design Overview:
I've an application with Invoice creation and Inventory management features in it. Design Overview:
我有一个具有发票创建和库存管理功能的应用程序。 Let's first understand the database design with 2 entities that we have as below:让我们首先了解具有以下两个实体的数据库设计:
Now, here I've a M:N relationship between these 2 entities because one invoice can contain multiple items and one item can be included in many such invoices.现在,我在这两个实体之间建立了 M:N 关系,因为一张发票可以包含多个项目,并且一个项目可以包含在许多这样的发票中。
So, I've created a 3rd table which we call joining table to associate these entities as shown in the image below,所以,我创建了第三个表,我们称之为连接表来关联这些实体,如下图所示,
Problem Statemet:
I'm unable to insert model in the child table(invoice_items) using include attribute. Problem Statemet:
我无法使用 include 属性在子表 (invoice_items)中插入 model。 Look at the code below to understand what's wrong happening here?查看下面的代码以了解这里发生了什么问题?
3 Model Classes as below: 3 Model 类如下:
1. Invoice:一、发票:
Note:
Providing with fewer attributes to keep it short. 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. Item: 2.项目:
Note:
Providing with fewer attributes to keep it short. 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: 3.发票项目:
Note:
Providing with fewer attributes to keep it short. 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; }
Now, I'm using below code to create an invoice with the list of items in it.现在,我正在使用下面的代码创建一个包含项目列表的发票。 But, this is not inserting the child records in the joining table(
invoice_items
).但是,这并不是在连接表 (
invoice_items
) 中插入子记录。 What's wrong here in the code below?下面的代码有什么问题?
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' }] });
After trying so many variations, I understand that there was a problem in the association of my model classes.在尝试了这么多变化之后,我了解到我的 model 类的关联存在问题。 And, below is the way of associating both
Invoice
and Item
model classes for M:N(Many to Many) relationships.并且,下面是将
Invoice
和Item
model 类关联为 M:N(多对多)关系的方式。 I can now update the join table(invoice_items) by inserting the record in it for each invoice we create in the system with the items in it.我现在可以更新连接表 (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 } }); };
Create Invoice with Items in it:创建包含项目的发票:
Note:
Passing itemId (1) as a parameter in the addItems() method. Note:
将 itemId (1) 作为参数传递到 addItems() 方法中。 If you have multiple items in an invoice then you can add forEach
loop here to iterate over each item and individually pass the itemId
, quantity
and rate
for an item sold to the customer.如果您在一张发票中有多个项目,那么您可以在此处添加
forEach
循环以遍历每个项目,并分别传递销售给客户的项目的itemId
、 quantity
和rate
。
// 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 } });
Database Tables with one Test Result:具有一个测试结果的数据库表:
1. Invoice Table: 1. 发票表:
2. Invoice_items Table(Join Table): 2. Invoice_items 表(连接表):
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.