【问题标题】:Getting error when using set on a hasMany association在 hasMany 关联上使用 set 时出错
【发布时间】:2020-04-25 07:20:33
【问题描述】:

我有一个Invoice 模型,它可以与多个LineItem 模型关联。当我调用setLineItems(lineItems, {transaction: t});(其中lineItemsLineItem 对象的数组)时,我收到一个错误,因为Sequelize 在scnenes 后面创建了一些非常奇怪的SQL:

DatabaseError [SequelizeDatabaseError]: invalid input syntax for integer: "[object Object]"
// Stack trace cut out
{
    name: 'error',
    length: 108,
    severity: 'ERROR',
    code: '22P02',
    detail: undefined,
    hint: undefined,
    position: '69',
    internalPosition: undefined,
    internalQuery: undefined,
    where: undefined,
    schema: undefined,
    table: undefined,
    column: undefined,
    dataType: undefined,
    constraint: undefined,
    file: 'numutils.c',
    line: '62',
    routine: 'pg_atoi',
    sql: `UPDATE "LineItems" SET "invoiceId"=$1,"updatedAt"=$2 WHERE "id" IN ('[object Object]', '[object Object]')`,
    parameters: [ 8, '2020-04-25 06:56:19.482 +00:00' ]
}

我的代码/定义如下:

invoice.js:

'use strict';
module.exports = (sequelize, DataTypes) => {
    const Invoice = sequelize.define('Invoice', {
        // various fields, including a numeric id
    }, {});
    Invoice.associate = function (models) {
        Invoice.hasMany(models.LineItem, { foreignKey: 'invoiceId' });
    };
    return Invoice;
};

lineItems.js:

'use strict';
module.exports = (sequelize, DataTypes) => {
    const LineItem = sequelize.define('LineItem', {
        id: {
            allowNull: false,
            autoIncrement: true,
            primaryKey: true,
            type: DataTypes.INTEGER
        },
        invoiceId: {
            type: DataTypes.INTEGER,
            references: {
                model: 'Invoices',
                key: 'id'
            },
        },
        hsnSacCode: DataTypes.STRING(30),
        desc: DataTypes.STRING(1500),
        qty: DataTypes.DECIMAL(10, 3),
        rate: DataTypes.DECIMAL(10, 3),
        amt: DataTypes.DECIMAL(16, 3)
    }, {});
    LineItem.associate = function (models) {
    };
    return LineItem;
};

Invoice 迁移:

'use strict';

const tbl = 'Invoices';

module.exports = {
    up: (queryInterface, Sequelize) => {
        return queryInterface.createTable(tbl, {
            id: {
                allowNull: false,
                autoIncrement: true,
                primaryKey: true,
                type: Sequelize.INTEGER
            },
            // other fields
        });
    },
    down: (queryInterface, Sequelize) => {
        return queryInterface.dropTable('Invoices');
    }
};

LineItem 迁移:

'use strict';
module.exports = {
    up: (queryInterface, Sequelize) => {
        return queryInterface.createTable('LineItems', {
            id: {
                allowNull: false,
                autoIncrement: true,
                primaryKey: true,
                type: Sequelize.INTEGER
            },
            invoiceId: {
                type: Sequelize.INTEGER,
                references: {
                    model: 'Invoices',
                    key: 'id'
                },
                onUpdate: 'CASCADE',
                onDelete: 'SET NULL'
            },
            hsnSacCode: {
                type: Sequelize.STRING(30)
            },
            desc: {
                type: Sequelize.STRING(1500)
            },
            qty: {
                type: Sequelize.DECIMAL(10,3)
            },
            rate: {
                type: Sequelize.DECIMAL(10,3)
            },
            amt: {
                type: Sequelize.DECIMAL(16,3)
            },
            createdAt: {
                allowNull: false,
                type: Sequelize.DATE
            },
            updatedAt: {
                allowNull: false,
                type: Sequelize.DATE
            }
        });
    },
    down: (queryInterface, Sequelize) => {
        return queryInterface.dropTable('LineItems');
    }
};

奇怪的是,生成的SQL竟然这么错误!!示例:

START TRANSACTION;
INSERT INTO "Invoices" ("id","invoiceNum","vendorId","corporateId","dated","currency","preTaxAmt","igstPct","sgstPct","totalAmt","tdsPaid","gstInputCreditClaimed","status","vendorStatus","type","createdAt","updatedAt") VALUES (DEFAULT,$1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13,$14,$15,$16) RETURNING *;
SELECT "id", "invoiceId", "hsnSacCode", "desc", "qty", "rate", "amt", "createdAt", "updatedAt" FROM "LineItems" AS "LineItem" WHERE "LineItem"."invoiceId" = 8;
UPDATE "LineItems" SET "invoiceId"=$1,"updatedAt"=$2 WHERE "id" IN ('[object Object]', '[object Object]')
ROLLBACK;

这是执行的代码:

const dbInvoice = await sequelize.transaction(async (t) => {
    const invoice = _.omit(input, ['lineItems']);
    const { lineItems } = _.pick(input, ['lineItems']);
    const dbInvoice = await Invoice.create(invoice, { transaction: t });
    console.log(`lineItems:`, lineItems);
    await dbInvoice.setLineItems(lineItems, {transaction: t});
    return Promise.resolve(dbInvoice.dataValues);
});

在我尝试保存之前lineItemsconsole.log 输出:

lineItems: [
  {
    hsnSacCode: 'arbit',
    desc: 'Daycare for Child1, Child2',
    qty: 2,
    rate: '2000.00',
    amt: '4000.00'
  },
  {
    hsnSacCode: 'arbit',
    desc: 'Daycare for Child1, Child2',
    qty: 1,
    rate: '2000.00',
    amt: '2000.00'
  }
]

如果我用刚刚保存的Invoiceid 填充每个lineItem,然后正常保存它们(即不使用setLineItems(...)),它会按预期工作。

使用 PostgresQL RDBMS。

续集:[节点:12.14.1,CLI:5.5.1,ORM:5.21.3

【问题讨论】:

  • 显示console.log的输出(lineItems:, lineItems);
  • @Anatoly 刚刚添加了lineItemsconsole.log 输出。
  • 如果您在创建之前尝试将 invoiceId: dbInvoice.id 添加到每个 lineItem 会怎样?
  • @Anatoly 我在调用setLineItems() 之前添加了lineItems.forEach(li => { li.invoiceId = dbInvoice.dataValues.id; }); 行,结果是一样的。 console.log() 输出显示添加的 invoiceId 字段设置为正确的值。
  • 还将 Sequelize 更新到版本 5.21.7(来自 5.21.3),但没有任何变化。

标签: sequelize.js


【解决方案1】:

您使用原始对象调用setItems(更重要的是,它们是新对象)。您需要致电addItems,然后 Sequelize 将插入它们并为您关联它们。

我希望setItems 聪明并为你创造了这些物品。似乎即使这些项目在数据库中,您也只能调用 setX 关联方法与空数组或 Sequelize 对象数组(而不是使用 id 字段手动创建的对象或从浏览器等)。

我怎么知道该调用哪一个?

执行此操作的最佳方法是先保存项目,然后再将它们添加到发票中。用代码松散地说:

// Save the items first.
let savedItems = [];
for(const item of items) {
  let savedItem;
  if(item.id) {
    savedItem = await sequelize.Item.save(item);
  } else {
    savedItem = await sequelize.Item.create(item);
  }
  savedItems.push(savedItem);
}

// Now this will work.
await Invoice.setItems(savedItems);

【讨论】:

  • 我会试试的。同时:我如何处理更新情况?有时发票的更新会想要添加新的lineItems,有时只是编辑现有的lineItems。你能用这方面的建议更新你的答案吗?
  • 那里。这样更好吗?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-09-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-12-08
  • 1970-01-01
相关资源
最近更新 更多