Nie wierz migracjom

Napisano: 16 maja 2010 21:40 Aktualizowano: 23 maja 2010 21:11

Migracje doctrinowe są narzędziem, które ma nam ułatwić wersjonowanie bazy danych. Dzięki nim można po zmianie schematu zmienić zarówno bazę na maszynie developerskiej, a później powtórzyć zmiany na produkcyjnej. Ale to narzędzie ma tylko ułatwić, nie wyręczyć. Wygeneruje klasy migracyjne ale na z góry określonych zasadach. Najpierw operacje na tabelach, później klucze i indeksy:

PHP code
  1. class Version12 extends Doctrine_Migration_Base
  2. {
  3.     public function up()
  4.     {
  5.         $this->createTable('model_a', array(
  6.              'id' =>
  7.              array(
  8.               'type' => 'integer',
  9.               'length' => '8',
  10.               'autoincrement' => '1',
  11.               'primary' => '1',
  12.              ),
  13.              'name' =>
  14.              array(
  15.               'type' => 'string',
  16.               'length' => '255',
  17.              ),
  18.              ), array(
  19.              'primary' =>
  20.              array(
  21.               0 => 'id',
  22.              ),
  23.              'collate' => 'utf8_general_ci',
  24.              'charset' => 'utf8',
  25.              ));
  26.         $this->createTable('model_b', array(
  27.              'id' =>
  28.              array(
  29.               'type' => 'integer',
  30.               'length' => '8',
  31.               'autoincrement' => '1',
  32.               'primary' => '1',
  33.              ),
  34.              'name' =>
  35.              array(
  36.               'type' => 'string',
  37.               'length' => '255',
  38.              ),
  39.              'a_id' =>
  40.              array(
  41.               'type' => 'integer',
  42.               'length' => '8',
  43.              ),
  44.              ), array(
  45.              'primary' =>
  46.              array(
  47.               0 => 'id',
  48.              ),
  49.              'collate' => 'utf8_general_ci',
  50.              'charset' => 'utf8',
  51.              ));
  52.     }
  53.  
  54.     public function down()
  55.     {
  56.         $this->dropTable('model_a');
  57.         $this->dropTable('model_b');
  58.     }
  59. }
  60.  
  61. class Version13 extends Doctrine_Migration_Base
  62. {
  63.     public function up()
  64.     {
  65.         $this->createForeignKey('model_b', 'model_b_a_id_model_a_id', array(
  66.              'name' => 'model_b_a_id_model_a_id',
  67.              'local' => 'a_id',
  68.              'foreign' => 'id',
  69.              'foreignTable' => 'model_a',
  70.              ));
  71.         $this->addIndex('model_b', 'model_b_a_id', array(
  72.              'fields' =>
  73.              array(
  74.               0 => 'a_id',
  75.              ),
  76.              ));
  77.     }
  78.  
  79.     public function down()
  80.     {
  81.         $this->dropForeignKey('model_b', 'model_b_a_id_model_a_id');
  82.         $this->removeIndex('model_b', 'model_b_a_id', array(
  83.              'fields' =>
  84.              array(
  85.               0 => 'a_id',
  86.              ),
  87.              ));
  88.     }
  89. }

Podejście to jest jak najbardziej w porządku, gdy dodajemy elementy do naszej struktury. Jeśli od niej coś odejmujemy, wygenerowane migracje następują w tej samej kolejności! Najpierw tabele, lub pola, są usuwane z bazy, a następnie usuwane są klucze obce i indeksy. Analogicznie wygenerowana migracja w operacji w dół próbuje najpierw stworzyć klucze obce, później dopiero tabelę.

PHP code
  1. class Version14 extends Doctrine_Migration_Base
  2. {
  3.     public function up()
  4.     {
  5.         $this->dropTable('model_a');
  6.     }
  7.  
  8.     public function down()
  9.     {
  10.         $this->createTable('model_a', array(
  11.              'id' =>
  12.              array(
  13.               'type' => 'integer',
  14.               'length' => '8',
  15.               'autoincrement' => '1',
  16.               'primary' => '1',
  17.              ),
  18.              'name' =>
  19.              array(
  20.               'type' => 'string',
  21.               'length' => '255',
  22.              ),
  23.              ), array(
  24.              'type' => '',
  25.              'indexes' =>
  26.              array(
  27.              ),
  28.              'primary' =>
  29.              array(
  30.               0 => 'id',
  31.              ),
  32.              'collate' => 'utf8_general_ci',
  33.              'charset' => 'utf8',
  34.              ));
  35.     }
  36. }
  37.  
  38. class Version15 extends Doctrine_Migration_Base
  39. {
  40.     public function up()
  41.     {
  42.         $this->dropForeignKey('model_b', 'model_b_a_id_model_a_id');
  43.     }
  44.  
  45.     public function down()
  46.     {
  47.         $this->createForeignKey('model_b', 'model_b_a_id_model_a_id', array(
  48.              'name' => 'model_b_a_id_model_a_id',
  49.              'local' => 'a_id',
  50.              'foreign' => 'id',
  51.              'foreignTable' => 'model_a',
  52.              ));
  53.     }
  54. }

Nie byłoby tragicznie, gdyby operacja migrowania była objęta transakcją, problem jest taki, że nie jest. I tak, jeśli uruchomimy błędną migrację, wykona nam ona wszystko co może, nawet, jeśli po drodze napotka błędy. W takim wypadku zostaniemy z, delikatnie mówiąc, rozsynchronizowaną bazą danych. By doprowadzić ją do porządku, konieczne jest poświęcenie więcej uwagi bazie, niż początkowo miało się na to nadzieję.

Pracując z migracjami, należy mieć na uwadze, iż narzędzie to ma nam, programistom czy projektantom pomóc w pracy, nie nas wyręczyć. Każdą migrację po wygenerowaniu powinno się dokładnie obejrzeć i być może poprawić lub dopisać np. działanie na danych.

Przed wgryzieniem się w migracje warto przeczytać również dokumentację doctrine na temat migracji.

Grzegorz Śliwiński

Skomentuj pierwszy!

Skomentuj!

Adres email nie zostanie opublikowany

Musi zaczynać się od http:// lub https://
Usuń odpowiedź