Переходы Laravel - отличный способ отключения проверки внешнего ключа

При выполнении миграций 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;');
    }
}

Проблема заключается в том, что утомительно писать, и он загромождает код.

Я также подумал о создании двух фиктивных файлов миграции, единственной целью которых было бы включить и отключить проверки внешнего ключа, и я бы назвал их таким образом, чтобы они запускались в начале и в конце каждого миграция.

Если есть изящное решение, можно ли применить его также к процессу посева, так как это тоже проблема.

Это, очевидно, очень импровизированное решение, и я спрашиваю, есть ли лучший способ сделать это. Существуют ли методы beforeMigrate и afterMigrate, которые я могу переопределить или что-то в этом роде?

И если нет, как вы это делаете?

Любые идеи будут оценены, мне не нравятся все варианты, о которых я говорил.

Ответ 1

У меня была аналогичная задача, когда Lumen/Laravel начал использовать Passport, и мне пришлось отказаться от предыдущей реализации oauth-сервера из lucadegasperi/oauth2-server-laravel.

Наконец-то мне удалось добиться успеха, создав 2 миграции, где первая очищает внешние ключи, а вторая фактически удаляет таблицы.

Мне нужно было использовать даты перед миграциями Laravel 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();
}
//...

Ответ 2

Я сделал это, извлекая логику внешнего ключа в отдельный файл миграции. Это помогло мне:

  • Отключить ограничения внешнего ключа.
  • Безопасное удаление базы данных, если она существует.

В коде:

//file: 2017_06_19_230601_fk_postuser_table.php

public function down()
{
        Schema::disableForeignKeyConstraints();
        Schema::dropIfExists('post_user');
}

Ответ 3

Еще один важный аспект, который следует помнить, - это опустить foreignKey FIRST, а затем столбец. Удаление столбца сначала вызывает ошибку:

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
        });
    }

Ответ 4

Иногда лучший способ это сделать - всегда добавлять созданные внешние ключи в код переноса отката.

Допустим, у вас есть внешний ключ в вашей схеме up следующим образом:

Schema::table('mytable', function (Blueprint $table) {
    $table->foreign(mycolumn)->references('id')->on(foreigntable);
}

В вашей миграции down, вы должны иметь

$table->dropForeign(mytable_mycolumn_foreign);//this is how laravel generates the foreign keys