Миграция: не удается добавить ограничение внешнего ключа в laravel

Я пытаюсь создать внешние ключи в Laravel, однако, когда я переношу свою таблицу с помощью artisan, я вызываю следующую ошибку:

[Illuminate\Database\QueryException]
SQLSTATE[HY000]: General error: 1215 Cannot add foreign key constraint (SQL
: alter table `priorities` add constraint priorities_user_id_foreign foreign 
key (`user_id`) references `users` (`id`))     

Мой код миграции выглядит так:

файл миграции приоритетов

public function up()
{
    //
    Schema::create('priorities', function($table) {
        $table->increments('id', true);
        $table->integer('user_id');
        $table->foreign('user_id')->references('id')->on('users');
        $table->string('priority_name');
        $table->smallInteger('rank');
        $table->text('class');
        $table->timestamps('timecreated');
    });
}

/**
 * Reverse the migrations.
 *
 * @return void
 */
public function down()
{
    //
    Schema::drop('priorities');
}

файл миграции пользователей

public function up()
{
    //
    Schema::table('users', function($table)
    {
    $table->create();
    $table->increments('id');
    $table->string('email');
    $table->string('first_name');
    $table->string('password');
    $table->string('email_code');
    $table->string('time_created');
    $table->string('ip');
    $table->string('confirmed');
    $table->string('user_role');
    $table->string('salt');
    $table->string('last_login');

    $table->timestamps();
    });
}

/**
 * Reverse the migrations.
 *
 * @return void
 */
public function down()
{
    //
        Schemea::drop('users');
}

Любые идеи относительно того, что я сделал неправильно, я хочу получить это прямо сейчас, поскольку у меня есть много таблиц, которые мне нужно создать, например. Пользователи, клиенты, проекты, задачи, статусы, приоритеты, типы, команды. В идеале я хочу создать таблицы, которые хранят эти данные с помощью внешних ключей, i..e clients_project и project_tasks и т.д.

Надеюсь, кто-то может помочь мне начать.

Спасибо заранее.

Ответ 1

Добавьте его в два шага, и хорошо также сделать его неподписанным:

public function up()
{
    Schema::create('priorities', function($table) {
        $table->increments('id', true);
        $table->integer('user_id')->unsigned();
        $table->string('priority_name');
        $table->smallInteger('rank');
        $table->text('class');
        $table->timestamps('timecreated');
    });

   Schema::table('priorities', function($table) {
       $table->foreign('user_id')->references('id')->on('users');
   });

}

Ответ 2

Вопрос уже ответил, но надеюсь, что это может помочь кому-то другому.

Эта ошибка произошла для меня, потому что я создал таблицу миграции с внешним ключом в ней, прежде чем ключ существовал как первичный ключ в исходной таблице. Миграции выполняются в том порядке, в котором они были созданы, как указано в имени файла, сгенерированном после запуска migrate:make. Например. 2014_05_10_165709_create_student_table.php.

Решением было переименовать файл с внешним ключом в более раннее время, чем файл с первичным ключом, как рекомендуется здесь: http://forumsarchive.laravel.io/viewtopic.php?id=10246

Думаю, мне также пришлось добавить $table->engine = 'InnoDB';

Ответ 3

В моем случае проблема заключалась в том, что в основной таблице уже были записи, и я заставлял новый столбец не быть NULL. Поэтому добавление → nullable() в новый столбец делало трюк. В вопросе пример будет примерно таким:

$table->integer('user_id')->unsigned()->nullable();

или

$table->unsignedInteger('user_id')->nullable();

Надеюсь, это поможет кому-то!

Ответ 4

Laravel ^ 5.8

Начиная с Laravel 5.8, заглушки миграции используют метод bigIncrements для идентификатора столбцы по умолчанию. Ранее столбцы идентификаторов создавались с использованием метод приращений.

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

Source: Migrations & bigIncrements


Пример

Представьте, что вы создаете простое приложение на основе ролей, и вам нужно сослаться на user_id в таблице PIVOT "role_user".

2019_05_05_112458_create_users_table.php

// ...

public function up()
{
    Schema::create('users', function (Blueprint $table) {

        $table->bigIncrements('id');

        $table->string('full_name');
        $table->string('email');
        $table->timestamps();
    });
}

2019_05_05_120634_create_role_user_pivot_table.php

// ...

public function up()
{
    Schema::create('role_user', function (Blueprint $table) {

        // this line throw QueryException "SQLSTATE[HY000]: General error: 1215 Cannot add foreign key constraint..."
        // $table->integer('user_id')->unsigned()->index();

        $table->bigInteger('user_id')->unsigned()->index(); // this is working
        $table->foreign('user_id')->references('id')->on('users')->onDelete('cascade');
    });
}

Как видите, закомментированная строка выдаст исключение запроса, потому что, как упоминалось в примечаниях по обновлению, столбцы внешнего ключа должны быть одного типа, поэтому вам нужно либо поменять приоритет ключ (в данном примере это user_id) к bigInteger в таблице role_user или измените метод bigIncrements на метод приращений в таблице users и используйте закомментированную строку в сводной таблице, это вам.


Я надеюсь, что смог прояснить этот вопрос для вас.

Ответ 5

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

...
$table->bigIncrements('id');
...

Поэтому мне пришлось изменить тип столбца


$table->bigInteger('id');

заставить мою миграцию с внешним ключом работать.

Это с laravel 5.8.2

Ответ 6

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

Дальше больше:

Когда вы создаете миграцию, у нее есть timestamp в начале. Допустим, вы создали кошку миграции, поэтому она будет выглядеть как 2015_08_19_075954_the_cats_time.php и имеет этот код

<?php

use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;

class TheCatsTime extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('cat', function (Blueprint $table) {
            $table->increments('id');
            $table->string('name');  
            $table->date('date_of_birth');
            $table->integer('breed_id')->unsigned()->nullable(); 
        });

        Schema::table('cat', function($table) {
        $table->foreign('breed_id')->references('id')->on('breed');
      });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::drop('cat');
    }
}

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

<?php

use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;

class BreedTime extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('breed', function (Blueprint $table) {
             $table->increments('id');    
             $table->string('name');
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::drop('breed');
    }
}

Кажется, что обе таблицы верны, но при запуске php artisan migrate. Это вызовет исключение, потому что миграция сначала создаст базовую таблицу в вашей базе данных, потому что вы сначала создали эту миграцию, и наша базовая таблица имеет ограничение внешнего ключа, которое будет искать дочернюю таблицу, а дочерняя таблица не существует, что, вероятно, исключение..

Так:

Сначала создайте миграцию дочерней таблицы.

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

php ремесленник мигрировать.

сделано это будет работать

Ответ 7

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

В папке базы данных/миграции/ваше имя файла миграции имеет следующий формат: year_month_day_hhmmss_create_XXXX_table.php

Просто переименуйте созданный файл пользователя, чтобы дата создания таблицы приоритетов таблиц была установлена ​​позже, чем дата пользователя (даже спустя одну секунду)

Ответ 8

У меня была та же проблема с использованием Laravel 5.8. После более пристального взгляда на документы по Laravel, более того, здесь Migrations & bigIncrements. Я решил это путем добавления первичных ключей "$table-> bigIncrements ('id')" к каждой отдельной таблице, которая связана с таблицей "пользователи" и ее ассоциациями, в моем случае с таблицей "роль". Наконец, у меня был "$table-> unsignedBigInteger" для связи ролей с пользователями ("многие ко многим"), то есть с таблицей "role_user".

1. Users table

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

2. Roles Table
    Schema::create('roles', function (Blueprint $table) {
        $table->bigIncrements('id');
        $table->string('name')->unique();
        $table->string('display_name')->nullable();
        $table->string('description')->nullable();
        $table->timestamps();
    });

3. Table role_user
Schema::create('role_user', function (Blueprint $table) {
            $table->unsignedBigInteger('user_id');
            $table->unsignedBigInteger('role_id');
            $table->foreign('user_id')->references('id')->on('users')
                ->onUpdate('cascade')->onDelete('cascade');
            $table->foreign('role_id')->references('id')->on('roles')
                ->onUpdate('cascade')->onDelete('cascade');
            $table->primary(['user_id', 'role_id']);
        });

Ответ 9

В laravel 5.8 users_table использует bigIncrements('id') для первичного ключа. Поэтому, когда вы хотите сослаться на ограничение внешнего ключа, ваш столбец user_id должен иметь тип unsignedBigInteger('user_id').

Ответ 10

Мы не можем добавлять отношения, пока не будут созданы связанные таблицы. Laravel запускает миграции по порядку файлов миграции. Поэтому, если вы хотите создать связь с таблицей, которая существует во 2-м файле миграции, это не удастся.

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

Schema::table('properties', function(Blueprint $table) {
        $table->foreign('user')->references('id')->on('users')->onDelete('cascade');
        $table->foreign('area')->references('id')->on('areas')->onDelete('cascade');
        $table->foreign('city')->references('id')->on('cities')->onDelete('cascade');
        $table->foreign('type')->references('id')->on('property_types')->onDelete('cascade');
    });

    Schema::table('areas', function(Blueprint $table) {
        $table->foreign('city_id')->references('id')->on('cities')->onDelete('cascade');
    });

Ответ 11

У меня была эта проблема с Laravel 5.8, и добавление этого кода туда, где я добавляю user_id, помогло.

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

тогда я побежал $ php artisan migrate:refresh

Ответ 12

Использование Laravel 5.3 имело ту же проблему.

Решение заключалось в использовании unsignedInteger вместо integer ('name') → unsigned().

Так вот что работает

$table->unsignedInt('column_name');
$table->foreign('column_name')->references('id')->on('table_name');

Причиной этого было то, что при использовании integer ('name') → unsigned столбец, созданный в таблице, имел длину 11, но при использовании unsigedInteger ('name' ) столбец имел длину 10.

Длина 10 - это длина для первичных ключей при использовании Laravel, поэтому длина столбцов соответствует.

Ответ 13

Для добавления ограничения внешнего ключа в laravel, для меня работало следующее:

  • Создайте столбец для внешнего ключа следующим образом:

    $table->integer('column_name')->unsigned();
  • Добавление строки ограничения сразу после (1) i.e.

    $table->integer('column_name')->unsigned();
    $table->foreign('column_name')->references('pk_of_other_table')->on('other_table');

Ответ 14

Эта ошибка возникла для меня, потому что - в то время как таблица, которую я пыталась создать, была InnoDB - внешняя таблица, которую я пыталась связать с ней, была таблицей MyISAM!

Ответ 15

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

$table->engine = 'InnoDB';

Ответ 16

Имейте в виду: когда Laravel устанавливает таблицу, используя

$table->increments('id');

что является стандартным в большинстве миграций, это установит поле целого числа без знака. Поэтому при создании внешней ссылки из другой таблицы на это поле убедитесь, что в ссылочной таблице вы задали для поля значение UnsignedInteger, а не (как я предполагал, поле) UnsignedBigInteger.

Например: в файле миграции 2018_12_12_123456_create_users_table.php:

Schema::create('users', function (Blueprint $table){
    $table->increments('id');
    $table->string('name');
    $table->timestamps();

Затем в файле миграции 2018_12_12_18000000_create_permissions_table.php, который устанавливает внешнюю ссылку для пользователей:

Schema::create('permissions', function (Blueprint $table){
    $table->increments('id');
    $table->UnsignedInteger('user_id'); // UnsignedInteger = "increments" in users table
    $table->boolean('admin');
    $table->boolean('enabled');
    $table->timestamps();

    // set up relationship
    $table->foreign('user_id')->reference('id')->on('users')->onDelete('cascade');
}

Ответ 17

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

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

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

Преимущество в изменении кода даты - ваш код перехода будет легче читать и поддерживать.

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

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

Итак, пример: файл 2016_01_18_999999_create_product_options_table. Для этого нужно создать таблицу продуктов. Посмотрите имена файлов.

 public function up()
{
    Schema::create('product_options', function (Blueprint $table) {
        $table->increments('id');
        $table->integer('product_attribute_id')->unsigned()->index();
        $table->integer('product_id')->unsigned()->index();
        $table->string('value', 40)->default('');
        $table->timestamps();
        //$table->foreign('product_id')->references('id')->on('products');
        $table->foreign('product_attribute_id')->references('id')->on('product_attributes');
        $table->foreign('product_id')->references('id')->on('products');


    });
}

/**
 * Reverse the migrations.
 *
 * @return void
 */
public function down()
{
    Schema::drop('product_options');
}

таблица продуктов: сначала ее необходимо перенести. 2015_01_18_000000_create_products_table

public function up()
{
    Schema::create('products', function (Blueprint $table) {
        $table->increments('id');

        $table->string('style_number', 64)->default('');
        $table->string('title')->default('');
        $table->text('overview')->nullable();
        $table->text('description')->nullable();


        $table->timestamps();
    });
}

/**
 * Reverse the migrations.
 *
 * @return void
 */
public function down()
{
    Schema::drop('products');
}

И, наконец, в самом конце файла, который я временно использую для решения проблем, которые я буду реорганизовывать, когда пишу тесты для моделей, которые я назвал 9999_99_99_999999_create_foreign_keys.php. Эти ключи прокомментированы, когда я вытащил их, но вы поняли.

    public function up()
    {
//        Schema::table('product_skus', function ($table) {
//            $table->foreign('product_id')->references('id')->on('products')->onDelete('cascade');
//    });

    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
//        Schema::table('product_skus', function ($table)
//        {
//            $table->dropForeign('product_skus_product_id_foreign');
//        });

Ответ 18

Так просто!!!

если ваш первый файл миграции 'priorities', первый запуск Laravel 'priorities' в то время как таблица 'users' не существует.

как он может добавить отношение к таблице, которая не существует!

Решение: вывести коды внешних ключей из таблицы 'priorities'. ваш файл миграции должен выглядеть следующим образом:

введите описание изображения здесь

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

public function up()
{        
    Schema::table('priorities', function (Blueprint $table) {          
        $table->foreign('user_id')
              ->references('id')
              ->on('users');                        
    });
}

Ответ 19

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

Я имею в виду, что ваш foreingkey (во второй таблице) должен быть того же типа вашего основного ключа ponter (в первой таблице)

ваш главный ключ указателя должен быть добавлен беззнаковый метод, позвольте мне показать:

в таблице ПЕРВОЙ миграции:

$table->increments('column_name'); //is INTEGER and UNSIGNED

в таблице SECOND migration:

$table->integer('column_forein_name')->unsigned(); //this must be INTEGER and UNSIGNED
$table->foreign('column_forein_name')->references('column_name')->on('first_table_name');

ДРУГОЙ ПРИМЕР ВИДЕТЬ РАЗЛИЧИЯ

в таблице ПЕРВОЙ миграции:

$table->mediumIncrements('column_name'); //is MEDIUM-INTEGER and UNSIGNED

в таблице SECOND migration:

$table->mediumInteger('column_forein_name')->unsigned(); //this must be MEDIUM-INTEGER and UNSIGNED
$table->foreign('column_forein_name')->references('column_name')->on('first_table_name');

СМОТРЕТЬ ТЯГОВЫЕ ТИПЫ ТИПОВ MYSQL

Ответ 20

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

Например, если одна таблица использует:

$table->engine = 'InnoDB';

А другой использует

$table->engine = 'MyISAM';

сгенерирует ошибку:

SQLSTATE[HY000]: General error: 1215 Cannot add foreign key constraint

Вы можете исправить это, просто добавив InnoDB в конце создания таблицы следующим образом:

public function up()
{
    Schema::create('users', function (Blueprint $table) {
        $table->bigIncrements('id');
        $table->unsignedInteger('business_unit_id')->nullable();

        $table->string('name', 100);

        $table->foreign('business_unit_id')
                ->references('id')
                ->on('business_units')
                ->onDelete('cascade');

        $table->timestamps();
        $table->softDeletes();
        $table->engine = 'InnoDB'; # <=== see this line
    });
}

Ответ 21

В моем случае я ссылался на столбец целочисленный id столбца строка user_id. Я изменил:

$table->string('user_id')

в

$table->integer('user_id')->unsigned();

Надеюсь, это поможет кому-то!

Ответ 22

В моем случае я забыл использовать скобки для ->unsigned(), когда я определил столбец.

Код Worng: $table->integer('permission_id')->unsigned;

Истинный код: $table->integer('permission_id')->unsigned();

Ответ 23

Суть заключается в том, что посторонний метод использует ALTER_TABLE, чтобы сделать ранее существовавшее поле во внешнем ключе. Таким образом, вы должны определить тип таблицы, прежде чем применять внешний ключ. Однако он не должен быть в отдельном вызове Schema::. Вы можете делать и то, и другое внутри create, например:

public function up()
{
    Schema::create('priorities', function($table) {
        $table->increments('id', true);
        $table->integer('user_id')->unsigned();
        $table->foreign('user_id')->references('id')->on('users');
        $table->string('priority_name');
        $table->smallInteger('rank');
        $table->text('class');
        $table->timestamps('timecreated');
    });
}

Также обратите внимание, что тип user_id устанавливается в unsigned для соответствия внешнему ключу.

Ответ 24

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

        $table->integer('user_id', false, true);

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

Ответ 25

Я сошел с ума, у меня просто была опечатка:

unsinged() вместо unsigned().

Ответ 26

Если ни одно из приведенных выше решений не bigInteger для новичков, проверьте, имеют ли оба идентификатора одинаковый тип: оба являются integer или оба являются bigInteger ,... Вы можете получить что-то вроде этого:

Основная таблица (пользователи, например)

$table->bigIncrements('id');

Детский стол (приоритеты например)

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

Этот запрос не удался, поскольку users.id является BIG INTEGER, тогда как priorities.user_id является INTEGER.

Правильный запрос в этом случае будет следующим:

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

Ответ 27

В моем случае это не сработало, пока я не запустил команду

composer dump-autoload

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

public function up()
{
    //
     Schema::create('priorities', function($table) {
        $table->increments('id', true);
        $table->integer('user_id');
        $table->foreign('user_id')->references('id')->on('users');
        $table->string('priority_name');
        $table->smallInteger('rank');
        $table->text('class');
        $table->timestamps('timecreated');
    });
 }

 /**
 * Reverse the migrations.
 *
 * @return void
 */
public function down()
{
    //
    Schema::drop('priorities');
}

Ответ 28

Это также может быть ваш заказ создания миграции. Если вы сначала создадите таблицу приоритетов, а затем таблицу пользователей, то это будет неправильно. Из-за первой миграции ищем таблицу пользователей. Таким образом, вы должны изменить порядок миграции на

app/database/migrations

каталог

Ответ 29

Вы должны написать таким образом

public function up()
{
    Schema::create('transactions', function (Blueprint $table) {
        $table->bigIncrements('id');
        $table->float('amount', 11, 2);
        $table->enum('transaction type', ['debit', 'credit']);
        $table->bigInteger('customer_id')->unsigned();      
        $table->timestamps();                 
    });

    Schema::table('transactions', function($table) {
        $table->foreign('customer_id')
              ->references('id')->on('customers')
              ->onDelete('cascade');
    });     
}

Поле внешнего ключа должно быть без знака, надеюсь, это поможет !!

Ответ 30

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

public function up()
{
    Schema::create('image_post', function (Blueprint $table) {
        $table->engine = 'InnoDB';
        $table->increments('id');
        $table->integer('image_id')->unsigned()->index();
        $table->integer('post_id')->unsigned()->index();
        $table->timestamps();
    });

    Schema::table('image_post', function($table) {
        $table->foreign('image_id')->references('id')->on('image')->onDelete('cascade');
        $table->foreign('post_id')->references('id')->on('post')->onDelete('cascade');
    });

}