一个迁移文件中的多个迁移语句

Posted

技术标签:

【中文标题】一个迁移文件中的多个迁移语句【英文标题】:Multiple migration statements in one migration file 【发布时间】:2016-02-03 19:31:17 【问题描述】:

我正在尝试在单个迁移文件中执行多个迁移语句,以便一次更改同一张表的多个列。

我想知道我是否以书面方式进行操作,或者是否有更好和更合适的方式

迁移代码

module.exports = 
    up: function(queryInterface, Sequelize, done) 

        queryInterface.changeColumn('users', 'name', 
            type: Sequelize.STRING,
            allowNull: false,
            require: true,
            unique: true
        ).success(function() 
            queryInterface.changeColumn('users', 'address', 
                type: Sequelize.STRING,
                allowNull: false,
                require: true,
                unique: true
            ).success(function() 
                queryInterface.changeColumn('users', 'city', 
                    type: Sequelize.STRING,
                    allowNull: false,
                    require: true,
                    unique: true
                ).success(function() 
                    queryInterface.changeColumn('users', 'state', 
                        type: Sequelize.STRING,
                        allowNull: false,
                        require: true,
                        defaultValue: "ncjnbcb"
                    );
                    done();
                );
            );
        );
    
;

但我遇到一个错误,上面写着:

TypeError: undefined is not a function

由于我在迁移中找不到任何调试错误的方法,如果有人帮助我解决它,或者如果可能的话,请告诉我们如何找出迁移中的错误。

【问题讨论】:

【参考方案1】:

您的 TypeError 可能是因为您没有返回任何内容。 docs 说每个迁移函数都应该返回一个 Promise。没有提到done 回调。

为此,请尝试以下操作:

return Promise.all([
  queryInterface.changeColumn..., 
  queryInterface.changeColumn...
]);

【讨论】:

请提供有用的反馈? 这个方法不太对。任何失败的查询都会导致迁移卡住。见github.com/sequelize/cli/issues/133#issuecomment-236402184 正如@KevinCarmody 所提到的,在一个文件中执行多个事务会使您面临进入不可恢复状态的风险。此外,使用Promise.all 将并行运行迁移。这些天你最好使用asyncawait 此时我的回答已经过时了。从某种意义上说,它解决了 OP 的主要问题是正确的,但请参阅其他答案以了解如何编写更好的实现。【参考方案2】:
module.exports = 
  up: async (queryInterface, Sequelize) => 
    try 
      await queryInterface.addColumn('User', 'name', 
        type: Sequelize.STRING
      );
      await queryInterface.addColumn('User', 'nickname', 
        type: Sequelize.STRING
      );
      return Promise.resolve();
     catch (e) 
      return Promise.reject(e);
    
  ,

  down: async (queryInterface, Sequelize) => 
    try 
      await queryInterface.removeColumn('Challenges', 'name');
      await queryInterface.removeColumn('Challenges', 'nickname');
      return Promise.resolve();
     catch (e) 
      return Promise.reject(e);
    
  
;

【讨论】:

【参考方案3】:

在事务中使用Promise.all(更安全的迁移):

module.exports = 
  up: async (queryInterface, Sequelize) => 
    return queryInterface.sequelize.transaction(t => 
      return Promise.all([
        queryInterface.changeColumn('users', 'name', 
           type: Sequelize.STRING ,
           transaction: t 
        ),
        queryInterface.changeColumn('users', 'address', 
           type: Sequelize.STRING ,
           transaction: t 
        ),
        queryInterface.changeColumn('users', 'city', 
           type: Sequelize.STRING ,
           transaction: t 
        )
      ]);
    );
  ,

  down: async (queryInterface, Sequelize) => 
    return queryInterface.sequelize.transaction((t) => 
      return Promise.all([
        queryInterface.removeColumn('users', 'name',  transaction: t ),
        queryInterface.removeColumn('users', 'address',  transaction: t ),
        queryInterface.removeColumn('users', 'city',  transaction: t )
      ])
    )
  
;

如果某些查询被拒绝,则在没有事务的情况下使用 Promise.all 会导致问题。使用事务是安全的,这样所有操作都会成功执行,否则不会进行任何更改。

【讨论】:

关于最后一句话,这应该是正确的答案 我尝试使用 return promise.all,但工作只是挂在那里。【参考方案4】:

所以这是 2 个答案的组合。

@Firmino Changani - 效果很好,但即使有些迁移失败也会完成一些迁移

@Aswin Sanakan - 表示它们都可以迁移,或者没有迁移,但如果第二次迁移依赖于第一次迁移,它将不起作用

我正在创建一个表并向该表添加一个特殊索引。所以我最终将它们结合起来,以下对我有用:

'use strict';
module.exports = 
  up: async (queryInterface, Sequelize) => 
    return queryInterface.sequelize.transaction(async t => 
      try 
        await queryInterface.createTable(
          'phonenumbers',
          
            id: 
              allowNull: false,
              autoIncrement: true,
              primaryKey: true,
              type: Sequelize.INTEGER
            ,
            full_number: 
              type: Sequelize.STRING,
              unique: true
            ,
            phone: 
              type: Sequelize.STRING
            ,
            extension: 
              type: Sequelize.INTEGER,
            ,
            country_id: 
              type: Sequelize.INTEGER
            ,
            is_valid_format: 
              type: Sequelize.BOOLEAN
            ,
            type: 
              type: Sequelize.STRING
            ,
            createdAt: 
              allowNull: false,
              type: Sequelize.DATE
            ,
            updatedAt: 
              allowNull: false,
              type: Sequelize.DATE
            ,
          ,
           transaction: t 
        ),
        await queryInterface.addIndex(
          'phonenumbers',
          ['phone'],
          
            name: 'constraint-phone-extension',
            where: extension: null,
            transaction: t
          
        )
        return Promise.resolve();
       catch (e) 
        return Promise.reject(e);
      
    );
  ,
  down: async (queryInterface, Sequelize) => 
    return queryInterface.sequelize.transaction(async t => 
      try 
        await queryInterface.dropTable('phonenumbers',  transaction: t ),
        return Promise.resolve();
       catch (e) 
        return Promise.reject(e);
      
    )
  
;

【讨论】:

以上是关于一个迁移文件中的多个迁移语句的主要内容,如果未能解决你的问题,请参考以下文章

laravel数据库迁移

运行nestjs应用程序时typeorm迁移中的“不能在模块外使用import语句”

表迁移

Laravel migrate - 一次完成多个迁移(文件)

django迁移问题

如何在一个 App 中迁移多个领域文件