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

114

Я пытаюсь создать внешние ключи в 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 и т.д.

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

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

Теги:
eloquent
migration
foreign-keys
laravel-4

29 ответов

254
Лучший ответ

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

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

}
  • 0
    о, спасибо, я не думал, что это было так просто. примет после того, как таймер тикает вниз.
  • 84
    Спасибо Антонио! Для меня проблема не заключалась в добавлении unsigned () в столбец user_id, чтобы он соответствовал типу данных столбца id в таблице users. Функция Laravel increments ('id') создает целое число без знака, поэтому столбец внешнего ключа также должен быть без знака.
Показать ещё 6 комментариев
94

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

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

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

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

  • 4
    После того, как вы переименуете файл миграции и получите несколько ошибок, таких как: Не удалось открыть поток: Нет такого файла или каталога (и отображается старое имя миграции), вы должны запустить: composer dump-autoload
  • 12
    $ table-> engine = 'InnoDB'; требуется для принудительного применения внешнего ключа на уровне MySql. Движок laravel по умолчанию - MyIsam, который не поддерживает внешние ключи!
Показать ещё 3 комментария
38

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

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

или

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

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

  • 0
    Обратите внимание, что столбец «id» в вашей родительской таблице также должен быть без знака! Использование строки, такой как $ table-> increments ('id'); автоматически по умолчанию будет без знака.
13

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

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

Когда вы создаете миграцию, у нее есть 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 ремесленник мигрировать.

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

11

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

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

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

4

Мы не можем добавлять отношения, пока не будут созданы связанные таблицы. 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');
    });
  • 1
    как вы назвали файл? 9999_99_99_999999_create_foreign_keys.php?
  • 0
    довольно простая причина, так что она всегда работает в конце всех миграций ...
Показать ещё 1 комментарий
4

Для добавления ограничения внешнего ключа в 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');
3

Использование 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, поэтому длина столбцов соответствует.

3

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

$table->engine = 'InnoDB';
2

убедитесь, что столбец 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

2

Перейдя сюда через несколько лет после первоначального вопроса, используя 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');
//        });
2

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

  • 0
    MyISAM не поддерживает ограничения внешнего ключа. Вероятно, это сработало, потому что переключение на MyISAM привело к тому, что он полностью проигнорировал внешний ключ, который, вероятно, существовал по какой-то причине. Быть осторожен.
1

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

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

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

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

1

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

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

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

1

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

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

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

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

Изображение 3550

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

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

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

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

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

1

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

$table->string('user_id')

в

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

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

0

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

Проверьте, существует ли таблица, и если нет, проверьте миграцию этой таблицы.

0

Имейте в виду: когда 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');
}
0

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

app/database/migrations

каталог

0

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

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

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

Вы должны создать столбец без знака, чтобы он работал.

0

Это решило мою проблему

Таблица или индекс, на которые ссылается ограничение, еще не существует

как сказал @haakym, единственное, что вам нужно сделать, это переименовать имя в xxx_xx_xx_xxxxxx_create_users_table и установить более раннюю дату, чем xxx_xx_xx_xxxxxx_create_priorities_table

не забудьте использовать $table->engine = 'InnoDB'; если вы используете MySql, потому что MyISAM не поддерживает внешние ключи ограничения

0

Если ни одно из приведенных выше решений не 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');
0

Добавление к решению unsigned() при создании базы данных с использованием InnoDB в качестве движка таблиц. Убедитесь, что внешняя таблица была создана до таблиц, которые будут зависеть от внешней таблицы.

иллюстрация

Случай 1 (свежие таблицы)

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

Случай 2 (уже существующие таблицы)

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

PS

Я полагаю, вы используете Laravel

0

Я думаю: ссылочным ключом должен быть "индекс". например: (вниз)

public function up()
{
    Schema::create('clicks', function (Blueprint $table) {
        $table->increments('id');
        $table->string('viewer_id');
        $table->integer('link_id')->index()->unsigned();
        $table->string('time');
        $table->timestamps();
    });

    Schema::table('clicks', function($table) {
        $table->foreign('link_id')->references('id')->on('links')->onDelete('cascade');
    });


}

удачи.

0

Суть заключается в том, что посторонний метод использует 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 для соответствия внешнему ключу.

0

У меня была такая же ошибка с Laravel 5 при создании сводной таблицы, и проблема в моем случае состояла в том, что у меня не было

->onDelete('cascade');

0

Одна вещь, о которой я думаю, отсутствует в ответах здесь, и, пожалуйста, исправьте меня, если я ошибаюсь, но внешние ключи нужно индексировать на сводной таблице. По крайней мере, в 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');
    });

}

Ещё вопросы

Сообщество Overcoder
Наверх
Меню