• Czas czytania ~3 min
  • 03.07.2023

Jeśli podczas migracji utworzysz klucze obce, może wystąpić sytuacja, że tabela zostanie utworzona pomyślnie, ale klucz obcy nie powiedzie się. Następnie migracja jest "w połowie udana", a jeśli ponownie uruchomisz ją po naprawie, powie "Tabela już istnieje". Co robić?


Problem: Wyjaśnione

Najpierw pozwól mi szczegółowo wyjaśnić problem. Oto przykład.

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

Kod wygląda dobrze, prawda? A co, jeśli tabela "team_leagues", do której następuje odwołanie, nie istnieje? A może nazywa się inaczej? Następnie zobaczysz ten błąd w terminalu:

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`))

Ale to tylko część problemu. Więc ok, zdałeś sobie sprawę, że przywoływana tabela nazywa się "ligi", a nie "team_leagues". Możliwe opcje naprawy:

  • Zmień nazwę pola "team_league_id" na "league_id"
  • Możesz też określić tabelę ->constrained('leagues')

Ale prawdziwym problemem jest teraz stan bazy danych:

  • Tabela teams jest już utworzona
  • Ale obcy klucz do lig zawiódł!

Oznacza to, że nie ma zapisu o tym sukcesie migracji w tabeli "migracje" Laravel system DB.

Teraz prawdziwy problem: jeśli naprawisz błąd w tej samej migracji i po prostu uruchomisz php artisan migrate, powie "Tabela już istnieje".

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` (...)

Czy należy utworzyć nową migrację? Wycofywanie? Pozwólcie, że wyjaśnię mój ulubiony sposób rozwiązania tego problemu.


Rozwiązanie: Schema::hasTable() i oddzielny klucz

obcy Możesz ponownie uruchomić migrację dla już istniejących tabel i upewnić się, że zostaną utworzone tylko wtedy, gdy nie istnieją z metodą Schema::hasTable() .

Ale potem musimy podzielić na foreignId() części, ponieważ jest to w rzeczywistości metoda 2 w 1: tworzy kolumnę (co się powiodło) i klucz obcy (który się nie powiódł).

Tak więc przepisujemy migrację na to:

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

Teraz, jeśli uruchomisz php artisan migrate, pomyślnie wykona pełną migrację.

Oczywiście alternatywnym rozwiązaniem byłoby ręczne usunięcie teams tabeli za pomocą klienta SQL i ponowne uruchomienie migracji z poprawką, ale nie zawsze masz dostęp do bazy danych, jeśli jest zdalna. Ponadto nie jest idealnym rozwiązaniem ręczne wykonywanie jakichkolwiek operacji na bazie danych, jeśli używasz migracji. Może to być w porządku w lokalnej bazie danych, ale powyższe rozwiązanie byłoby uniwersalne dla wszystkich lokalnych/zdalnych baz danych.

Comments

No comments yet
Yurij Finiv

Yurij Finiv

Full stack

O

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...

O autorze CrazyBoy49z
WORK EXPERIENCE
Kontakt
Ukraine, Lutsk
+380979856297