• Время чтения ~1 мин
  • 03.07.2023

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


Проблема: объяснение

Во-первых, позвольте мне подробно объяснить проблему. Вот пример.

Schema::create('teams', function (Blueprint $table) {
    $table->id();
    $table->string('name');
    $table->foreignId('team_league_id')->constrained();
    $table->timestamps();
});

Код выглядит неплохо, правда? А что, если таблица, на которую указывает «team_leagues», не существует? А может по-другому называется? Тогда вы увидите эту ошибку в терминале:

2023_06_05_143926_create_teams_table ..................................................................... 20ms FAIL
Illuminate\Database\QueryException
  SQLSTATE[HY000]: General error: 1824 Failed to open the referenced table 'team_leagues'
  (Connection: mysql, SQL: alter table `teams` add constraint `teams_team_league_id_foreign` foreign key (`team_league_id`) references `team_leagues` (`id`))

Но это только часть проблемы. Итак, хорошо, вы поняли, что упомянутая таблица называется «лиги», а не «team_leagues». Возможные варианты исправления:

  • Либо переименуйте поле «team_league_id» в просто «league_id»
  • Или укажите таблицу ->constrained('leagues')

Но реальная проблема сейчас заключается в состоянии базы данных:

  • Таблица teams уже создана
  • Но иностранный ключ к лигам провалился!

Это означает, что в таблице баз данных системы Laravel нет записей об успешном завершении миграции.

Теперь реальная проблема: если вы исправите ошибку в той же миграции и просто запустите php artisan migrate, он скажет: «Таблица уже существует».

2023_06_05_143926_create_teams_table ...................................................................... 3ms FAIL
Illuminate\Database\QueryException
  SQLSTATE[42S01]: Base table or view already exists:
  1050 Table 'teams' already exists
  (Connection: mysql, SQL: create table `teams` (...)

Так стоит ли создавать новую миграцию? Откат? Позвольте мне объяснить мой любимый способ решения этой проблемы.


Решение: Schema::hasTable() и отдельный внешний ключ

Вы можете повторно запустить миграцию для уже существующих таблиц и убедиться, что они будут созданы только в том случае, если они не существуют с помощью метода Schema::hasTable() .

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

Итак, мы переписываем миграцию в это:

if (! Schema::hasTable('teams')) {
    Schema::create('teams', function (Blueprint $table) {
        $table->id();
        $table->string('name');
        $table->unsignedBigInteger('team_league_id');
        $table->timestamps();
    });
}
// This may be in the same migration file or in a separate one
Schema::table('teams', function (Blueprint $table) {
    $table->foreign('team_league_id')->constrained('leagues');
});

Теперь, если вы запустите php artisan migrate, он успешно выполнит полную миграцию.

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

Comments

No comments yet
Yurij Finiv

Yurij Finiv

Full stack

Про мене

Professional Fullstack Developer with extensive experience in website and desktop application development. Proficient in a wide range of tools and technologies, including Bootstrap, Tailwind, HTML5, CSS3, PUG, JavaScript, Alpine.js, jQuery, PHP, MODX, and Node.js. Skilled in website development using Symfony, MODX, and Laravel. Experience: Contributed to the development and translation of MODX3 i...

Об авторе CrazyBoy49z
WORK EXPERIENCE
Контакты
Ukraine, Lutsk
+380979856297