Po kilku nadmiernie przemyślanych i zbyt sprytnych próbach rozwiązania, myślę, że poniższe jest wykonalnym rozwiązaniem problemu.
tl;dr:
- Migracje Bookend po obu stronach migracji, które budują schemat z niczego.
- Zaktualizuj projekt.
- Migracja.
- Usuń podpórki i wszystkie poprzednie migracje.
- Usuń rekordy z
migrations
stół.
Pierwsza podpórka do książki zmienia nazwy stołów, których to dotyczy. Druga podpórka kopiuje dane z tabel ze zmienioną nazwą do nowych tabel, a następnie usuwa tabele ze zmienioną nazwą.
Uwaga:w podpórkach do książek możesz robić, co chcesz, to tylko minimum.
Załóżmy więc, że w przypadku migracji powiedzmy coś takiego:
- 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
Utworzylibyśmy kolejną migrację:
- 2017_09_05_000004_pre_refresh.php
Stworzylibyśmy kolejną migrację w oparciu o wiedzę, którą mamy teraz:
- 2017_09_05_000005_create_some_table.php
Stworzylibyśmy ostatnią podpórkę, w której nastąpi migracja danych:
- 2017_09_05_000006_post_refresh.php
Pierwsze cztery migracje nie zostaną uruchomione, ponieważ już zostały.
/** 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);
}
}
}
Nie ma potrzeby obniżania, ponieważ jest to transakcja jednorazowa. To zostanie uruchomione jako pierwsze, co powinno spowodować zmianę nazwy wszystkich tabel wymienionych w tablicy. Następnie zostanie uruchomiona skonsolidowana (zoptymalizowana) migracja.
/** 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');
}
}
}
Po uruchomieniu możesz usunąć wszystkie migracje z pre_refresh
i wcześniejsze. Jak również post_refresh
. Następnie możesz przejść do migrations
tabeli i usuń wpisy dla tych migracji.
Usunięcie wpisów nie jest całkowicie konieczne, ale jeśli migrate:rollback
otrzymasz komunikaty o błędach informujące, że nie można znaleźć migracji.
Ostrzeżenia
- Jeśli architektura nie jest z założenia modułowa, może być dość nieporęczna. Jeśli jednak podzieliłeś swój kod na usługi, wydaje się to trochę łatwiejsze.
- Obsługa błędów Laravela i komunikaty podczas migracji są bardzo ograniczone; więc debugowanie może być trudne.
- Zdecydowanie zalecamy rozpoczęcie od najbardziej stabilnych tabel w Twojej aplikacji/usługi. Co więcej, rozpoczęcie od tych, które są fundamentalne dla Twojej aplikacji, może również okazać się korzystne.
Uwaga:kiedy faktycznie robię to w środowisku produkcyjnym, a nie tylko w moim lokalnym (w kółko) i jeśli nie ma lepszej odpowiedzi, zaakceptuję to.
Rozważania
Jeśli dzielisz swoją aplikację na dostawców usług za pomocą dyskretnych migracji, możesz zakomentować dostawcę usług w /config/app
po uruchomieniu migracji. W ten sposób utworzysz partię dla usługi z podstawową wartością. Załóżmy więc, że masz następujące migracje, w których każda litera reprezentuje migrację, a każda zduplikowana litera reprezentuje tę samą usługę:
- A
- B
- C
- A
- C
- B
- A
Po konsolidacji usługi A:
- B
- C
- C
- B
- A
Po konsolidacji B:
- C
- C
- A
- B
Po konsolidacji C:
- A
- B
- C
aktualizacja
54 migracje do 27 dotychczas. Wyciągnąłem nawet kilka zmian schematu z dużego up()
i down()
metody i uczynić je oddzielnymi migracjami. Miłym efektem ubocznym są tu partie. Przeprowadziłem migrację, zaczynając od tabel podstawowych, na których obsługiwane jest wszystko inne; dlatego wycofywanie to bardziej usługa według usługi.