2017-01-22 105 views
4

使用sequelize cli实用程序的迁移功能时,可以通过添加新列来创建新的外键。但是,当我尝试为同一个模型创建多个外键时,我遇到了一个错误。通过运行sequelize db:migrate生成的外键名称并不具有独特性。数据库引擎要求所有的外键被分配一个唯一的名称,但SequelizeJS似乎initally命名所有外键:SequelizeJS迁移:将多个外键添加到相同的模型?

// Excerpt from sequelize/lib/dialects/mysql/query-generator.js 
// Line 195 
{fkName: this.quoteIdentifier(attrName + '_foreign_idx')} 

,这当然会产生相同的密钥,如果指数idx不正确递增。

在使用db.sync()初始化模型时,在Sequelize库中的某处,部分_foreign_idx必须替换为实际数值,但我无法确定位置。我还验证了使用db.sync()时,通过检查另一个数据库中的外键,sequelize确实会增加索引值。在这个数据库中,外键,分别命名为_ibfk_1_ibfk_2,..,_ibfk_n

  • 有没有人遇到过在国外密钥生成 产生相同名称的问题?
  • 有没有人有一个建议如何 这可以避免/缓解使用Sequelize迁移?

我使用的是MySQL作为数据库引擎,但外键名称生成器遵循例如相同的过程。就我所能解释的续集源代码而言,也是postgre。

以下迁移将创建三个模型和使用功能addColumn函数从sequelize cli创建它们之间的关系。

脚本模型,其中既有教练团队被一些赞助商赞助的情景。在这个模型中,我们希望在教练和球队模型中都参考赞助商ID。不幸的是,这将会创建两个名为sponsorId_foreign_idx的外键(一个在教练上,另一个在团队模型上),因此这些外键不会有唯一的名字。但是,如果idx被某个递增值更改,则可以避免这种情况。

var Promise = require('bluebird'); 

module.exports = { 
    up: function (queryInterface, Sequelize) { 
    return Promise 
     .join(
     queryInterface 
      .createTable('sponsor', { 
      id: { 
       autoIncrement: true, 
       primaryKey: true, 
       type: Sequelize.INTEGER 
      }, 
      name: { 
       type: Sequelize.STRING 
      }, 
      }), 
     queryInterface 
      .createTable('team', { 
      id: { 
       autoIncrement: true, 
       primaryKey: true, 
       type: Sequelize.INTEGER 
      }, 
      name: { 
       type: Sequelize.STRING 
      }, 
      }), 
     queryInterface 
      .createTable('coach', { 
      id: { 
       autoIncrement: true, 
       primaryKey: true, 
       type: Sequelize.INTEGER 
      }, 
      name: { 
       type: Sequelize.STRING 
      }, 
      }) 
    ) 
     .then(function(){ 
     return queryInterface 
      .addColumn('team', 'sponsorId', { 
      type: Sequelize.INTEGER, 
      references: { model: 'sponsor', key: 'id' } 
      }) 
      .then(function(){ 
      return queryInterface 
       .addColumn('coach', 'sponsorId', { 
       type: Sequelize.INTEGER, 
       references: { model: 'sponsor', key: 'id' } 
       }); 
      }); 
     }); 
    }, 

    down: function (queryInterface, Sequelize) { 
    return queryInterface.dropAllTables(); 
    } 
}; 

完整的错误日志转储

{ SequelizeBaseError: ER_DUP_KEY: Can't write; duplicate key in table '#sql-3b7_f1' 
    at Query.formatError (/home/usr/me/node_modules/sequelize/lib/dialects/mysql/query.js:175:14) 
    at Query._callback (/home/usr/me/node_modules/sequelize/lib/dialects/mysql/query.js:49:21) 
    at Query.Sequence.end (/home/usr/me/node_modules/mysql/lib/protocol/sequences/Sequence.js:86:24) 
    at Query.ErrorPacket (/home/usr/me/node_modules/mysql/lib/protocol/sequences/Query.js:94:8) 
    at Protocol._parsePacket (/home/usr/me/node_modules/mysql/lib/protocol/Protocol.js:280:23) 
    at Parser.write (/home/usr/me/node_modules/mysql/lib/protocol/Parser.js:74:12) 
    at Protocol.write (/home/usr/me/node_modules/mysql/lib/protocol/Protocol.js:39:16) 
    at Socket.<anonymous> (/home/usr/me/node_modules/mysql/lib/Connection.js:109:28) 
    at emitOne (events.js:96:13) 
    at Socket.emit (events.js:188:7) 
    at readableAddChunk (_stream_readable.js:176:18) 
    at Socket.Readable.push (_stream_readable.js:134:10) 
    at TCP.onread (net.js:551:20) 
    name: 'SequelizeDatabaseError', 
    message: 'ER_DUP_KEY: Can\'t write; duplicate key in table \'#sql-3b7_f1\'', 
    parent: 
    { Error: ER_DUP_KEY: Can't write; duplicate key in table '#sql-3b7_f1' 
     at Query.Sequence._packetToError (/home/usr/me/node_modules/mysql/lib/protocol/sequences/Sequence.js:52:14) 
     at Query.ErrorPacket (/home/usr/me/node_modules/mysql/lib/protocol/sequences/Query.js:83:18) 
     at Protocol._parsePacket (/home/usr/me/node_modules/mysql/lib/protocol/Protocol.js:280:23) 
     at Parser.write (/home/usr/me/node_modules/mysql/lib/protocol/Parser.js:74:12) 
     at Protocol.write (/home/usr/me/node_modules/mysql/lib/protocol/Protocol.js:39:16) 
     at Socket.<anonymous> (/home/usr/me/node_modules/mysql/lib/Connection.js:109:28) 
     at emitOne (events.js:96:13) 
     at Socket.emit (events.js:188:7) 
     at readableAddChunk (_stream_readable.js:176:18) 
     at Socket.Readable.push (_stream_readable.js:134:10) 
     at TCP.onread (net.js:551:20) 
     -------------------- 
     at Protocol._enqueue (/home/usr/me/node_modules/mysql/lib/protocol/Protocol.js:141:48) 
     at Connection.query (/home/usr/me/node_modules/mysql/lib/Connection.js:214:25) 
     at /home/usr/me/node_modules/sequelize/lib/dialects/mysql/query.js:40:21 
     at Promise._execute (/home/usr/me/node_modules/bluebird/js/release/debuggability.js:300:9) 
     at Promise._resolveFromExecutor (/home/usr/me/node_modules/bluebird/js/release/promise.js:481:18) 
     at new Promise (/home/usr/me/node_modules/bluebird/js/release/promise.js:77:14) 
     at Query.run (/home/usr/me/node_modules/sequelize/lib/dialects/mysql/query.js:39:17) 
     at /home/usr/me/node_modules/sequelize/lib/sequelize.js:849:20 
     at /home/usr/me/node_modules/retry-as-promised/index.js:40:21 
     at Promise._execute (/home/usr/me/node_modules/bluebird/js/release/debuggability.js:300:9) 
     at Promise._resolveFromExecutor (/home/usr/me/node_modules/bluebird/js/release/promise.js:481:18) 
     at new Promise (/home/usr/me/node_modules/bluebird/js/release/promise.js:77:14) 
     at retryAsPromised (/home/usr/me/node_modules/retry-as-promised/index.js:30:10) 
     at /home/usr/me/node_modules/sequelize/lib/sequelize.js:848:12 
     at tryCatcher (/home/usr/me/node_modules/bluebird/js/release/util.js:16:23) 
     at Promise._settlePromiseFromHandler (/home/usr/me/node_modules/bluebird/js/release/promise.js:510:31) 
    code: 'ER_DUP_KEY', 
    errno: 1022, 
    sqlState: '23000', 
    index: 0, 
    sql: 'ALTER TABLE `coach` ADD `sponsorId` INTEGER, ADD CONSTRAINT `sponsorId_foreign_idx` FOREIGN KEY (`sponsorId`) REFERENCES `sponsor` (`id`);' }, 
    original: 
    { Error: ER_DUP_KEY: Can't write; duplicate key in table '#sql-3b7_f1' 
     at Query.Sequence._packetToError (/home/usr/me/node_modules/mysql/lib/protocol/sequences/Sequence.js:52:14) 
     at Query.ErrorPacket (/home/usr/me/node_modules/mysql/lib/protocol/sequences/Query.js:83:18) 
     at Protocol._parsePacket (/home/usr/me/node_modules/mysql/lib/protocol/Protocol.js:280:23) 
     at Parser.write (/home/usr/me/node_modules/mysql/lib/protocol/Parser.js:74:12) 
     at Protocol.write (/home/usr/me/node_modules/mysql/lib/protocol/Protocol.js:39:16) 
     at Socket.<anonymous> (/home/usr/me/node_modules/mysql/lib/Connection.js:109:28) 
     at emitOne (events.js:96:13) 
     at Socket.emit (events.js:188:7) 
     at readableAddChunk (_stream_readable.js:176:18) 
     at Socket.Readable.push (_stream_readable.js:134:10) 
     at TCP.onread (net.js:551:20) 
     -------------------- 
     at Protocol._enqueue (/home/usr/me/node_modules/mysql/lib/protocol/Protocol.js:141:48) 
     at Connection.query (/home/usr/me/node_modules/mysql/lib/Connection.js:214:25) 
     at /home/usr/me/node_modules/sequelize/lib/dialects/mysql/query.js:40:21 
     at Promise._execute (/home/usr/me/node_modules/bluebird/js/release/debuggability.js:300:9) 
     at Promise._resolveFromExecutor (/home/usr/me/node_modules/bluebird/js/release/promise.js:481:18) 
     at new Promise (/home/usr/me/node_modules/bluebird/js/release/promise.js:77:14) 
     at Query.run (/home/usr/me/node_modules/sequelize/lib/dialects/mysql/query.js:39:17) 
     at /home/usr/me/node_modules/sequelize/lib/sequelize.js:849:20 
     at /home/usr/me/node_modules/retry-as-promised/index.js:40:21 
     at Promise._execute (/home/usr/me/node_modules/bluebird/js/release/debuggability.js:300:9) 
     at Promise._resolveFromExecutor (/home/usr/me/node_modules/bluebird/js/release/promise.js:481:18) 
     at new Promise (/home/usr/me/node_modules/bluebird/js/release/promise.js:77:14) 
     at retryAsPromised (/home/usr/me/node_modules/retry-as-promised/index.js:30:10) 
     at /home/usr/me/node_modules/sequelize/lib/sequelize.js:848:12 
     at tryCatcher (/home/usr/me/node_modules/bluebird/js/release/util.js:16:23) 
     at Promise._settlePromiseFromHandler (/home/usr/me/node_modules/bluebird/js/release/promise.js:510:31) 
    code: 'ER_DUP_KEY', 
    errno: 1022, 
    sqlState: '23000', 
    index: 0, 
    sql: 'ALTER TABLE `coach` ADD `sponsorId` INTEGER, ADD CONSTRAINT `sponsorId_foreign_idx` FOREIGN KEY (`sponsorId`) REFERENCES `sponsor` (`id`);' }, 
    sql: 'ALTER TABLE `coach` ADD `sponsorId` INTEGER, ADD CONSTRAINT `sponsorId_foreign_idx` FOREIGN KEY (`sponsorId`) REFERENCES `sponsor` (`id`);' } 
+0

您是否曾经找到合适的解决方法?看起来像[已在v4开发版中修复](https://github.com/sequelize/sequelize/pull/6008),但不在v3中。 –

+0

我使用'queryInterface.sequelize.query'([它在github页面上提到的存在](https://github.com/sequelize/cli)]公开的接口写出了定制的SQL查询。 – jorgenkg

回答

2

一些挖后,我发现,在this is a bug介绍v3.21。有人友好fixed it in the v4 alpha branch但不是在当前版本分支的v3中。我为v3提交了backport of the patch,但它需要一段时间才能发布。

与此同时,我采取了像上面评论中推荐的那样的手动查询。这不是太痛苦,因为它只影响在现有表上添加/更改查询,而不影响新表上的外键。

这些示例在文档中有些模糊,所以对于其他可能在这个问题中偶然发现的问题,这里是我从umzug迁移中得到的。

up: function (queryInterface, Sequelize) { 
    return queryInterface 
     .addColumn('operators', 'organization_id', { 
      type: Sequelize.INTEGER, 
      allowNull: true, 
      // This bit will cause the naming conflict 
      // references: { model: 'organizations', key: 'id' }, 
      // onUpdate: 'CASCADE', 
      // onDelete: 'RESTRICT' 
     }) 
     .then(() => queryInterface 
      .sequelize 
      .query('ALTER TABLE `operators` ADD CONSTRAINT `operators_organization_id_foreign_idx` FOREIGN KEY (`organization_id`) REFERENCES `organizations` (`id`) ON DELETE RESTRICT ON UPDATE CASCADE;', 
       { type: Sequelize.QueryTypes.RAW })); 
},