将迁移更改列续集为 FK,然后撤消失败

Posted

技术标签:

【中文标题】将迁移更改列续集为 FK,然后撤消失败【英文标题】:Sequelize migration changing column to be FK and then undo failing 【发布时间】:2021-03-28 14:45:06 【问题描述】:

我正在尝试创建迁移文件以将 changeColumn 更改为字符串(来自枚举)并引用其他表。

const enumStatus = ['PENDING', 'SUCCESSFUL', 'FAILED', 'FAILED_LAST_VALUE_MISSING', 'FAILED_LAST_DATE_MISSING', 'FAILED_OLD_LAST_DATE'];

module.exports = 
  up: async(queryInterface, Sequelize) => 
    return Promise.all([
      queryInterface.changeColumn('MeasurementTestResults', 'status', 
        type: Sequelize.STRING,
        allowNull: false
      ), queryInterface.addConstraint('MeasurementTestResults', 
        fields: ['status'],
        type: 'foreign key',
        name: 'statusFk',
        references: 
          table: 'MeasurementTestResultStatusEnums',
          field: 'code'
        ,
        onDelete: 'cascade',
        onUpdate: 'cascade'
      )
    ]);
  ,

  down: async(queryInterface, Sequelize) => 
    return Promise.all([
      queryInterface.removeConstraint('MeasurementTestResults', 'statusFk'),
      queryInterface.changeColumn('MeasurementTestResults', 'status', 
        type: Sequelize.ENUM(...enumStatus),
        allowNull: false
      )
    ]);
  
;

db:migrate 运行完美,但是当我尝试调用 db:migrate:undo 时,它会乱序执行命令?

== 20201217194748-measurementTestResult_changeColumn_status: reverting =======
Executing (default): SELECT CONSTRAINT_CATALOG AS constraintCatalog, CONSTRAINT_NAME AS constraintName, CONSTRAINT_SCHEMA AS constraintSchema, CONSTRAINT_TYPE AS constraintType, TABLE_NAME AS tableName, TABLE_SCHEMA AS tableSchema from INFORMATION_SCHEMA.TABLE_CONSTRA
INTS WHERE table_name='MeasurementTestResults' AND constraint_name = 'statusFk' AND TABLE_SCHEMA = 'iot_crcm_application_data1';
Executing (default): ALTER TABLE `MeasurementTestResults` CHANGE `status` `status` ENUM('PENDING', 'SUCCESSFUL', 'FAILED', 'FAILED_LAST_VALUE_MISSING', 'FAILED_LAST_DATE_MISSING', 'FAILED_OLD_LAST_DATE') NOT NULL;
Executing (default): ALTER TABLE `MeasurementTestResults`
      DROP FOREIGN KEY `statusFk`;

ERROR: (conn=143438, no: 1832, SQLState: HY000) Cannot change column 'status': used in a foreign key constraint 'statusFk'
sql: ALTER TABLE `MeasurementTestResults` CHANGE `status` `status` ENUM('PENDING', 'SUCCESSFUL', 'FAILED', 'FAILED_LAST_VALUE_MISSING', 'FAILED_LAST_DATE_MISSING', 'FAILED_OLD_LAST_DATE') NOT NULL; - parameters:[]

然后,当我尝试从脚本中删除 queryInterface.removeConstraint('MeasurementTestResults', 'statusFk'), 这一行时,它可以工作,但在我尝试出错之前没有...

【问题讨论】:

【参考方案1】:

不要尝试使用Promise.all 并行执行相互依赖的结构更改。你最好一一称呼:

await queryInterface.removeConstraint('MeasurementTestResults', 'statusFk')
await queryInterface.changeColumn('MeasurementTestResults', 'status', 
   type: Sequelize.ENUM(...enumStatus),
   allowNull: false
)

up 方法也是如此。

【讨论】:

如此简单但有效,非常感谢。这对我来说很新,这是我的第一个 up down 脚本。 如果 MariaDB 支持结构更改,请不要忘记添加事务。

以上是关于将迁移更改列续集为 FK,然后撤消失败的主要内容,如果未能解决你的问题,请参考以下文章

处理续集迁移和初始化的工作流程?

如何撤消上一个添加迁移命令?

如何使用 GRDB Swift 迁移更改列类型?

Laravel 5 迁移 - 外键约束失败

即使在运行迁移后,Django Programming 错误列也不存在

Django 迁移失败