Laravel Migration Неправильно сформировано ограничение внешнего ключа

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

Код

 public function up()
    {
        Schema::create('meals', function (Blueprint $table) {
            $table->increments('id');
            $table->integer('user_id')->unsigned();
            $table->integer('category_id')->unsigned();
            $table->string('title');
            $table->string('body');
            $table->string('meal_av');
            $table->timestamps();

            $table->foreign('user_id')
                ->references('id')
                ->on('users')
                ->onDelete('cascade');

            $table->foreign('category_id')
                ->references('id')
                ->on('categories')
                ->onDelete('cascade');
        });
    }  

Сообщение об ошибке

[Illuminate\Database\QueryException]                                         
      SQLSTATE[HY000]: General error: 1005 Can't create table `meal`.`#sql-11d2_1  
      4` (errno: 150 "Foreign key constraint is incorrectly formed") (SQL: alter   
      table `meals` add constraint meals_category_id_foreign foreign key (`catego  
      ry_id`) references `categories` (`id`) on delete cascade) 

29 ответов

Решение

@JuanBonnett Ваш вопрос вдохновил меня на ответ. Я решил использовать laravel для автоматизации процесса без учета времени создания самого файла. В соответствии с рабочим процессом блюда будут созданы перед таблицей (категориями), потому что я создал файл схемы (блюда) перед категориями. это была моя вина.

При создании новой таблицы в Laravel. Миграция будет сгенерирована следующим образом:

$table->bigIncrements('id');

Вместо (в старых версиях Laravel):

$table->increments('id');

Когда используешь bigIncrements внешний ключ ожидает bigInteger вместо целого числа. Итак, ваш код будет выглядеть так:

public function up()
    {
        Schema::create('meals', function (Blueprint $table) {
            $table->increments('id');
            $table->unsignedBigInteger('user_id'); //changed this line
            $table->unsignedBigInteger('category_id'); //changed this line
            $table->string('title');
            $table->string('body');
            $table->string('meal_av');
            $table->timestamps();

            $table->foreign('user_id')
                ->references('id')
                ->on('users')
                ->onDelete('cascade');

            $table->foreign('category_id')
                ->references('id')
                ->on('categories')
                ->onDelete('cascade');
        });
    }  

Вы также можете использовать increments вместо bigIncrements как сказал Кико Седжо.

Разница между Integer и BigInteger заключается в размере:

  • int => 32-разрядный
  • bigint => 64-битный

Вы должны создать свою миграцию для того, чтобы я users иметь role_id поле, которое от моего roles Таблица

Я сначала начинаю делать свою ролевую миграциюphp artisan make:migration create_roles_table --create=roles

тогда моя вторая миграция пользователейphp artisan make:migration create_users_table --create=users

php artisan migration выполнит, используя порядок созданных файлов2017_08_22_074128_create_roles_table.php и 2017_08_22_134306_create_users_table, проверяя порядок даты и времени, который будет порядком выполнения.

файлы 2017_08_22_074128_create_roles_table.php

public function up()
{
    Schema::create('roles', function (Blueprint $table) {
        $table->increments('id');
        $table->string('name', 50);
        $table->timestamps();
    });
}

2017_08_22_134306_create_users_table

public function up()
{
    Schema::create('users', function (Blueprint $table) {
        $table->increments('id');
        $table->integer('role_id')->unsigned();
        $table->string('name');
        $table->string('phone', 20)->unique();
        $table->string('password');
        $table->rememberToken();
        $table->boolean('active');
        $table->timestamps();
        $table->foreign('role_id')->references('id')->on('roles');
    });
}

Я получил то же сообщение для проблемы с типом данных.

Я использовал bigIncrements () для 'id', и когда я использовал его как внешний ключ (использовал bigInteger ()), я получил ошибку.

Я нашел решение, bigIncrements () возвращает unsignedBigInteger. Поэтому необходимо использовать unsignedBigInteger () вместо bigInteger () во внешнем ключе

Поделиться этим, потому что это может помочь другим

Просто добавь ->unsigned()->index() в конце внешнего ключа, и он будет работать

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

//this didn't work
$table->integer('id')->unique();
$table->primary('id');

//this worked
$table->integer('id')->unsigned()->unique();
$table->primary('id');

//this worked 
$table->increments('id');

Если вы используете ->onDelete('set null') в своем определении внешнего ключа убедитесь, что само поле внешнего ключа nullable() т.е.

//Column definition
$table->integer('user_id')->unsigned()->index()->nullable(); //index() is optional

//...
//...

//Foreign key 
$table->foreign('user_id')
      ->references('id')
      ->on('users')
      ->onDelete('set null');

Ларавелла 5.8

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

 public function up()
    {
        Schema::create('questions', function (Blueprint $table) {
            $table->bigIncrements('id');
             $table->text('body');
             $table->integer('user_id')->unsigned();
            $table->timestamps();
        });
    }

Таблица ответов выглядит так:

public function up()
{
    Schema::create('replies', function (Blueprint $table) {
        $table->bigIncrements('id');
        $table->text('body');
        $table->unsignedBigInteger('question_id');
        $table->integer('user_id')->unsigned();
        $table->foreign('question_id')->references('id')->on('questions')->onDelete('cascade');
        $table->timestamps();
    });
}

В моем случае новая конвенция Laravel вызвала эту ошибку.

Просто путем обмена таблицей id сделал свое дело.

$table->increments('id'); // ok

, вместо:

$table->bigIncrements('id'); // was the error.

Уже работаю с Laravel v5.8, никогда не было этой ошибки раньше.

Миграции должны быть созданы сверху вниз.

Сначала создайте миграции для таблиц, которые никому не принадлежат.

Затем создайте миграции для таблиц, которые принадлежат предыдущим.


Упрощенный ответ на проблему движка таблицы:

Чтобы установить механизм хранения для таблицы, установите свойство механизма в построителе схемы:

Schema::create('users', function ($table) {
    $table->engine = 'InnoDB';

    $table->increments('id');
});

Из Документов Laravel: https://laravel.com/docs/5.2/migrations

Мне пришлось столкнуться с той же проблемой на Larvel 6. Я решаю это следующим образом.

Думаю, это поможет вам или другим:

$table->increments('id');
    $table->bigInteger('user_id')->unsigned(); //chnage this line
    $table->bigInteger('category_id')->unsigned(); //change this line
    ---
    $table->foreign('user_id')
        ->references('id')
        ->on('users')
        ->onDelete('cascade');
    $table->foreign('category_id')
        ->references('id')
        ->on('categories')
        ->onDelete('cascade');

Увеличение идентификатора с использованием эквивалента "большого целого числа".

использовал bigInteger вместо Integer

  1. Если все еще сейчас, у вас есть ошибка.

Я предлагаю вам изменить порядок файла миграции следующими способами:

Измените даты, которые образуют первую часть имен файлов миграции, чтобы они были в нужном вам порядке (например: для 2020_07_28_133303_update_categories.php дата и время 2020-07-28, 13:33:03);

NB: Сначала должен быть файл миграции "категорий", а не "Файл миграции".

В моем случае проблема заключалась в том, что одна из упомянутых таблиц была InnoDB, а другая - MyISAM.

MyISAM не поддерживает отношения с внешними ключами.

Итак, теперь обе таблицы InnoDB. Задача решена.

Laravel 6: обновление 17 января 2020 г.

$table->bigInteger( 'category_id' )->unsigned();

Это сработало для меня

Я использую Laravel 8 и имел ту же ошибку. Проблема в том, что оба этих столбца, например users.id и food.user_id, где user_id - внешний ключ, должны быть одинаковыми.

Users.id выглядит так:

      Schema::create('users', function (Blueprint $table) {
    $table->increments('id');
    $table->string('name');
    $table->string('email')->unique();
    $table->timestamp('email_verified_at')->nullable();
    $table->string('password');
    $table->rememberToken();
    $table->timestamps();
});

В mySql id - это не подписанный AUTO ICREMENT Int(10).

Если мы перейдем в другую таблицу, где мы хотим установить внешний ключ, например, тот, что ниже, я также изменил user_id на unsigned (). Раньше я писал это просто $table->integer('user_id') и это дало мне исключение, но теперь вы не столкнетесь с этой ошибкой, потому что они оба Int(10) и Unsigned:

      Schema::create('users_permissions', function (Blueprint $table) {
    $table->integer('user_id')->unsigned();
    $table->integer('permission_id')->unsigned();

    //Foreign Key Constraints
    $table->foreign('user_id')->references('id')->on('users')->onDelete('cascade');
    $table->foreign('permission_id')->references('id')->on('permissions')->onDelete('cascade');



    //Setting the primary keys
    $table->primary(['user_id','permission_id']);


}); 

Может быть, это может помочь любому, кто приземлится здесь: я только что столкнулся с такой же проблемой, и в моем случае это было то, что я установил (составное) уникальное ограничение на столбец внешнего ключа ДО ограничения внешнего ключа. Я решил проблему, поместив "уникальное" заявление после "иностранного" заявления.

Работает:

$table->foreign('step_id')->references('id')->on('steps')->onDelete('cascade');
$table->unique(['step_id','lang']);

Не работает:

$table->unique(['step_id','lang']);
$table->foreign('step_id')->references('id')->on('steps')->onDelete('cascade');

Я просто использую $table->unsignedBigInteger('user_id'); и решите это. (Laravel 5.8)

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

Один из способов обойти ошибки внешнего ключа - отключить проверку: "SET FOREIGN_KEY_CHECKS". Это паллиативное решение, но на самом деле правильнее всего настроить таблицы и их взаимосвязь.

   DB::statement('SET FOREIGN_KEY_CHECKS=0;');

   Schema::table('example', function (Blueprint $table) {

        $table->integer('fk_example')->unsigned()->index();
        $table->foreign('fk_example')->references('id')->on('examples');
    });

  DB::statement('SET FOREIGN_KEY_CHECKS=1;');

Я только что добавил

      $table->engine = 'MyISAM';

Это сработало. Это потому, что laravel по умолчанию создает таблицы с помощью InnoDB Engine.

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

Если вы все еще сталкиваетесь с проблемой, используйте это

        $table->foreignId('project_id')
                ->constrained()
                ->onUpdate('cascade')
                ->onDelete('cascade');

Он просто найдет эту таблицу и добавит к ней внешний ключ, это работает.

Добавьте ->nullable() в свое поле и убедитесь, что все поля, на которые вы ссылаетесь, действительно существуют.

Помните, что это важно, чтобы ссылочные поля и поля ссылок имели одинаковый тип данных.

Сначала вы должны создать таблицу категорий и пользователей при создании "блюд".

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


образец:

2019_04_10_050958_create_users_table 
2019_04_10_051958_create_categories_table
2019_04_10_052958_create_meals_table

Это простой вопрос, так что дайте простой ответ и перестаньте болтать о кустах, измените свой пример $table->integer('user_id')->unsigned(); к $table->BigInteger('user_id')->unsigned();для решения ошибки внешнего ключа. поэтому измените целое число на BigInteger в файле миграции...

  1. Проверка в справочной таблице базы данных должна иметь первичный ключ && автоинкремент
  2. Отбросьте таблицу, которую вы хотите перенести, и снова запустите перенос.

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

Не работает

      // Referenced table
Schema::create('budgets', function (Blueprint $table) {
        $table->id();
        $table->timestamps();
        $table->softDeletes();
});

// The other table
    Schema::create('payment', function (Blueprint $table) {
        $table->engine = 'InnoDB';
        $table->integer('budget_id')->unsigned()->nullable();
        $table->foreign('budget_id')
            ->references('id')
            ->on('budgets')
            ->onDelete('cascade');
        $table->timestamps();
});

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

Это работает

      // Referenced table
Schema::create('budgets', function (Blueprint $table) {
        $table->engine = 'InnoDB';
        $table->id();
        $table->timestamps();
        $table->softDeletes();
});

// The other table
    Schema::create('payment', function (Blueprint $table) {
        $table->engine = 'InnoDB';
        $table->integer('budget_id')->unsigned()->nullable();
        $table->foreign('budget_id')
            ->references('id')
            ->on('budgets')
            ->onDelete('cascade');
        $table->timestamps();
});

Использование Laravel 9~

Я исправил свой, установив идентификатор с приращением и присвоив внешнему ключу значение unsignedInteger, а затем отсортировал файл миграции в соответствующем порядке.

Мое решение было основано на решении @Swooth и @Muhammad Tareq.

      public function up()
{
    Schema::create('cart_items', function (Blueprint $table) {
        $table->increments('id');
        $table->unsignedInteger('session_id')->index();
        $table->foreign('session_id')->references('id')->on('shopping_sessions')
            ->onDelete('cascade');
}

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

Другие вопросы по тегам