是否使用 MySQL 对 bulkCreate returns 生成的 ID 进行后续处理?

Sequelize bulkCreate returns generated IDs or not with MySQL?

当我阅读 Sequelize docs it makes me think the generated IDs cannot be returned from a call to bulkCreate. Even the returning option parameter says it's a Postgres-only feature. This is also referenced in this Sequelize issue.

但我 运行 下面的代码,使用 Sequelize v5.21.3 和 MySQL 5.6.49,它似乎工作得很好(注意 我不是甚至传递 returning: true 选项。)

const MyEntity = sequelize.define(
  "MyEntity",
  {
    name: {
      type: DataTypes.STRING(255),
      allowNull: false
    },
  },
  {
    tableName: "my_entity"
  }
);
await MyEntity.sync();

const saved = await MyEntity.bulkCreate([
  { name: "test1" },
  { name: "test2" },
  { name: "test3" }
]);
console.log(`*** SAVED:\n ${JSON.stringify(saved, null, 2)}`);

它似乎正确 return id 的打印:

*** SAVED:
 [
  {
    "id": 1,
    "name": "test1",
    "createdAt": "2020-09-29T14:04:27.127Z",
    "updatedAt": "2020-09-29T14:04:27.127Z"
  },
  {
    "id": 2,
    "name": "test2",
    "createdAt": "2020-09-29T14:04:27.127Z",
    "updatedAt": "2020-09-29T14:04:27.127Z"
  },
  {
    "id": 3,
    "name": "test3",
    "createdAt": "2020-09-29T14:04:27.127Z",
    "updatedAt": "2020-09-29T14:04:27.127Z"
  }
]

那么真相是什么?我是否可以相信 returning id 将起作用,而不管我尝试插入多少条记录?文档的这一部分是否有误或措辞不当?

The success handler is passed an array of instances, but please notice that these may not completely represent the state of the rows in the DB. This is because MySQL and SQLite do not make it easy to obtain back automatically generated IDs and other default values in a way that can be mapped to multiple records. To obtain Instances for the newly created values, you will need to query for them again.

Sequelize 代码对 MariaDB 不返回带有插入的 ID 有一些解决方法,假设它们将按顺序创建,有一条评论说

//ONLY TRUE IF @auto_increment_increment is set to 1 !!

作为旁注,有趣的是不可配置和硬编码以递增 1...

./sequelize/lib/dialects/mariadb/query.js

  formatResults(data) {
    let result = this.instance;

    // update and upsert code....

    if (this.isInsertQuery(data)) {

      this.handleInsertQuery(data);

      if (!this.instance) {
        // handle bulkCreate AI primary key
        if (this.model
          && this.model.autoIncrementAttribute
          && this.model.autoIncrementAttribute === this.model.primaryKeyAttribute
          && this.model.rawAttributes[this.model.primaryKeyAttribute]
        ) {
          //ONLY TRUE IF @auto_increment_increment is set to 1 !!
          //Doesn't work with GALERA => each node will reserve increment (x for first server, x+1 for next node ...
          const startId = data[this.getInsertIdField()];
          result = new Array(data.affectedRows);
          const pkField = this.model.rawAttributes[this.model.primaryKeyAttribute].field;

// *** THIS SEQUENTIAllY INCREMENTS THE ID *** //
          for (let i = 0; i < data.affectedRows; i++) {
            result[i] = { [pkField]: startId + i };
          }
          return [result, data.affectedRows];
        }

        return [data[this.getInsertIdField()], data.affectedRows];
      }
    }

    //... more code

此代码描述 table 以获得上述代码所基于的 table 的 auto_increment 值。

./sequelize/lib/dialects/abstract/query-generator.js

  describeTableQuery(tableName, schema, schemaDelimiter) {
    const table = this.quoteTable(
      this.addSchema({
        tableName,
        _schema: schema,
        _schemaDelimiter: schemaDelimiter
      })
    );

    return `DESCRIBE ${table};`;
  }

describeTable()方法中调用了describeTableQuery()/sequelize/lib/dialects/abstract/query-abstract.js


  async describeTable(tableName, options) {
//... code
    const sql = this.queryGenerator.describeTableQuery(tableName, schema, schemaDelimiter);
    options = { ...options, type: QueryTypes.DESCRIBE };

    try {
      const data = await this.sequelize.query(sql, options);
// ...more code

MariaDB 方言 类 中有更多代码可以解决不直接从数据库返回的 ID。