【问题标题】:Laravel migrations nice way of disabling foreign key checksLaravel 迁移禁用外键检查的好方法
【发布时间】:2016-03-21 19:11:07
【问题描述】:

在运行 laravel 迁移时,我遇到了一点不便。我使用 Laravel 5.1。

由于有很多表有很多关系,我可能不可能重命名迁移文件,以便它们以正确的顺序运行,因此不会违反外键约束。这是我过去做过的一次,非常不切实际。

我现在正在做的是像这样定义每个迁移:

class CreateSomeTable extends Migration
{
    public function up()
    {
        DB::statement('SET FOREIGN_KEY_CHECKS=0;');
        // my table definitions go here
        DB::statement('SET FOREIGN_KEY_CHECKS=1;');
    }

    public function down()
    {
        DB::statement('SET FOREIGN_KEY_CHECKS=0;');
        // drop table
        DB::statement('SET FOREIGN_KEY_CHECKS=1;');
    }
}

这样做的问题是写起来很乏味,而且代码混乱。

我还考虑过创建两个虚拟迁移文件,其唯一目的是启用和禁用外键检查,我会以这样的方式命名它们,以便它们在每个文件的开头和结尾运行迁移。

如果有一个优雅的解决方案,是否也可以将其应用到播种过程中,因为这往往也是一个问题。

这显然是一个非常即兴的解决方案,我想问是否有更好的方法来做到这一点。是否有一些我可以覆盖的 beforeMigrateafterMigrate 方法或类似的方法?

如果没有,你会怎么做呢?

任何见解都将不胜感激,我不喜欢我所说的所有选项。

【问题讨论】:

  • 如果您使用 artisan 创建迁移并且它们具有正确的时间戳,它们应该始终以正确的顺序运行。它们按照时间戳的顺序运行..
  • 是的,这就是我提到文件顺序时的意思。问题是,有时你没有按正确的顺序生成它们,或者有时你可能有一个循环依赖,即两个表都有相互引用的外键。无论您以什么顺序运行该示例,除非您禁用检查,否则您将违反外键约束。
  • 避免此问题的最佳方法是先创建一个表创建迁移,然后再创建一个创建/删除键的迁移。
  • 不是特别相关,但您也可以通过这种方式禁用外键检查:\DB::getSchemaBuilder()->disableForeignKeyConstraints()。不确定是否有更好的方法来调用此方法。
  • 我又遇到了同样的问题,还有另一个项目。作为临时黑客,我正在按照 OP 中的建议进行操作; 2 个虚拟迁移文件,时间戳在其他所有操作之前和之后运行,分别关闭和打开外键检查。我认为 Laravel 的迁移系统存在根本缺陷。查看所有这些文件之间拆分的表创建代码既丑陋又不方便。从现在开始,我将把所有东西都放在一个迁移文件中,在开始和结束时禁用和启用外键检查,并且所有模式逻辑都清晰地排列在它们之间。

标签: php laravel migration


【解决方案1】:

要记住的另一个重要方面是先删除 foreignKey,然后是列。首先删除列会引发错误:

Cannot drop index 'tableName_columnName_foreign': needed in a foreign key constraint

正确的顺序很重要:

    public function down()
    {
        Schema::table('tableName', function (Blueprint $table) {
            $table->dropForeign(['columnName']); // fk first

            $table->dropColumn('columnName'); // then column
        });
    }

【讨论】:

    【解决方案2】:

    我通过将外键逻辑提取到单独的迁移文件中来完成此操作。这帮助我:

    • 禁用外键约束。
    • 安全删除数据库(如果存在)。

    在代码中:

    //file: 2017_06_19_230601_fk_postuser_table.php
    
    public function down()
    {
            Schema::disableForeignKeyConstraints();
            Schema::dropIfExists('post_user');
    }
    

    【讨论】:

      【解决方案3】:

      当 Lumen / Laravel 开始使用 Passport 时,我手头有一个类似的任务,我不得不从 lucadegasperi/oauth2-server-laravel 放弃以前的 oauth 服务器实现。

      我终于设法通过创建 2 个迁移来让事情顺利进行,其中第一个清除外键,第二个实际删除表。

      我必须在 Laravel's Passport (2016-06-01) 的迁移之前使用日期,因此它们将在这些之前执行。

      2016_05_31_000000_clear_old_oauth_relations.php

      //...
      class ClearOldOauthRelations extends Migration
      {
          public function up()
          {
              Schema::disableForeignKeyConstraints();
              // drop foreign keys
              Schema::table('oauth_access_tokens', function (BluePrint $table) {
                  $table->dropForeign('oauth_access_tokens_session_id_foreign');
              });
              //...
              Schema::enableForeignKeyConstraints();
          }
          //...
      }
      

      在第二个文件中 2016_05_31_000001_clear_old_oauth.php

      //...
      public function up()
      {
          Schema::disableForeignKeyConstraints();
          Schema::drop('oauth_access_tokens');
          //...
          Schema::enableForeignKeyConstraints();
      }
      //...
      

      【讨论】:

      • 这真是太好了!这个是最近才添加的,还是在 laravel 里有一段时间了,只是在遇到这个问题的时候没注意到?
      • 嗨@Pavlin,我不知道这是什么时候在 Laravel / Lumen 中添加的。请注意,您需要在例如中查找外键约束的名称。 PhpMyAdmin(结构 -> 关系)
      • 这是从 Laravel 5.2 开始添加的
      猜你喜欢
      • 2016-11-01
      • 1970-01-01
      • 2016-03-23
      • 2020-06-05
      • 2014-12-13
      • 2016-06-06
      • 2019-09-23
      • 2016-02-11
      • 2019-01-31
      相关资源
      最近更新 更多