• Час читання ~2 хв
  • 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 DB.

Тепер справжня проблема: якщо виправити помилку в тій же міграції і просто запустити 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` (...)

Отже, чи варто створювати нову міграцію? Відкочування? Дозвольте мені пояснити мій улюблений спосіб вирішення цієї проблеми.


Рішення: Схема::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