Mysql
 sql >> Database >  >> RDS >> Mysql

Laravel 5.5 Consolida le migrazioni con il database di produzione

Dopo un paio di tentativi di soluzione eccessivamente ingegnerizzati ed eccessivamente intelligenti, penso che la seguente sia una soluzione praticabile al problema.

tl;dr:

  • Migrazioni Bookend su entrambi i lati delle migrazioni che creano lo schema dal nulla.
  • Aggiorna progetto.
  • Migra.
  • Elimina i reggilibri e tutte le migrazioni precedenti.
  • Elimina i record da migrations tavolo.

Il primo fermalibri rinomina le tabelle interessate. Il secondo fermalibri copia i dati dalle tabelle rinominate alle nuove tabelle, quindi elimina le tabelle rinominate.

Nota:puoi fare quello che vuoi all'interno dei reggilibri, questo è solo un minimo.

Quindi, diciamo qualcosa come il seguente per le migrazioni:

  • 2017_09_05_000000_create_some_table.php
  • 2017_09_05_000001_add_field_x_to_some_table.php
  • 2017_09_05_000002_add_field_y_to_some_table.php
  • 2017_09_05_000003_add_field_z_to_some_table.php

Creeremmo un'altra migrazione:

  • 2017_09_05_000004_pre_refresh.php

Creeremmo un'altra migrazione in base alle conoscenze che abbiamo ora:

  • 2017_09_05_000005_create_some_table.php

Creeremo l'ultimo fermalibri, dove avverrà la migrazione dei dati:

  • 2017_09_05_000006_post_refresh.php

Le prime quattro migrazioni non verranno eseguite perché lo sono già state.

/** 2017_09_05_000004_pre_refresh.php */
class PreRefresh extends Migration
{
    public function up()
    {
        $prefix = 'zz_';
        $tablesToRename = [
            'foos',
            'bars'
        ];

        foreach($tablesToRename as $table) {
            Schema::rename($table, $prefix . $table);
        }
    }
}

Non c'è bisogno di un down, perché questo è un affare one shot. Questo verrà eseguito per primo, il che dovrebbe comportare la ridenominazione di tutte le tabelle elencate nell'array. Quindi verranno eseguite le migrazioni consolidate (ottimizzate).

/** 2017_09_05_000006_post_refresh.php */
class PostRefresh extends Migration
{
    public function up()
    {
        // Do what you need to do.
        // If you cannot use your models, just use DB::table() commands.

        $foos = DB::table('zz_foos')->get();
        foreach ($foos as $foo) {
            DB::table('foo')->insert([
                    'id'         => $foo->id,
                    'created_at' => $foo->created_at,
                    'updated_at' => $foo->updated_at
                ]);
        }

        $bars = DB::table('zz_bars')->get();
        foreach ($bars as $bar) {
            DB::table('bar')->insert([
                    'id'         => $bar->id,
                    'created_at' => $bar->created_at,
                    'updated_at' => $bar->updated_at,
                    'foo_id'     => $bar->foo_id
                ]);
        }

        // Tear down.
        $prefix = 'zz_';
        $tablesToRename = [
            'foo',
            'bar'
        ];

        foreach ($tablesToRename as $table) {
            DB::statement('SET FOREIGN_KEY_CHECKS=0');
            Schema::dropIfExists($prefix . $table);
            DB::statement('SET FOREIGN_KEY_CHECKS=1');
        }
    }
}

Dopo averlo eseguito, puoi eliminare tutte le tue migrazioni da pre_refresh e precedente. Oltre a post_refresh . Quindi puoi andare nelle migrations tabella ed elimina le voci per tali migrazioni.

L'eliminazione delle voci non è del tutto necessaria, ma se migrate:rollback riceverai messaggi di errore che indicano che la migrazione non può essere trovata.

Avvertenze

  1. Se l'architettura non è modulare in base alla progettazione, può essere piuttosto ingombrante. Tuttavia, se hai separato il codice in servizi, sembra essere un po' più semplice.
  2. La gestione degli errori e i messaggi di Laravel durante le migrazioni sono molto limitati; quindi, il debug potrebbe essere difficile.
  3. Consiglio vivamente di iniziare con le tabelle più stabili nella tua app/servizio. Inoltre, anche iniziare con quelli che sono fondamentali per la tua app potrebbe rivelarsi utile.

Nota:quando lo faccio effettivamente in produzione, non solo nel mio locale (più e più volte), e se non c'è una risposta migliore, lo accetterò.

Considerazioni

Se stai suddividendo la tua applicazione in fornitori di servizi con migrazioni discrete, puoi commentare il fornitore di servizi in /config/app quando esegui le migrazioni. In questo modo crei un batch per il servizio ora di base. Quindi, supponiamo che tu abbia le seguenti migrazioni in cui ogni lettera rappresenta una migrazione e ogni lettera duplicata rappresenta lo stesso servizio:

  • A
  • B
  • C
  • A
  • C
  • B
  • A

Dopo aver consolidato il servizio A:

  • B
  • C
  • C
  • B
  • A

Dopo aver consolidato B:

  • C
  • C
  • A
  • B

Dopo aver consolidato C:

  • A
  • B
  • C

aggiornamento

54 migrazioni fino a 27 finora. Ho anche estratto alcune modifiche allo schema da up() di grandi dimensioni e down() metodi e renderli migrazioni separate. Il bel effetto collaterale qui sono i lotti. Ho migrato a partire dalle tabelle di base su cui è supportato tutto il resto; pertanto, il rollback è più servizio per servizio.