Миграция: не удается добавить ограничение внешнего ключа в 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');
});
}