4

私たちはドクトリン移行を使用していますが、移行に複数のアクションが含まれていて、そのうちの1つが失敗すると、問題が発生することがよくあります。

たとえば、5つの外部キーを追加する移行があり、フィールドの長さが同じでないときに5つ目が失敗した場合、フィールドでエラーを修正して移行を再生成しても全体は修正されませが、エラーが発生します。キーの4つがすでに存在し、移行を正常に実行できないことに関連しています。

前述のような明らかな問題なしにDoctrineの移行を使用する安定した方法はありますか?以前はファイルを使用.sqlしていましたが、実際にはそれほど良くはありませんが、Doctrineを使用するプロジェクトのデータベースバージョン管理の正しい方法があると確信していますか?

モデルとスキーマの違いに基づいて移行を生成することは素晴らしいことであり、この可能性をさらに維持したいと思います。

ありがとう

4

3 に答える 3

2

私はこれを解決しました。解決策はそれほど素晴らしいものではありませんが、それでも、他の人にとっては役立つと思います。私はCLIを使用しています。実際、すべての移行でデータベース内の番号を更新するファイルを作成しました。これは、この質問をする前のTimoの回答と同様ですが、それでもあまり効果的ではありませんが、とにかく行う価値があります。

私が次に行ったことは、問題を解決し doctrine/lib/Doctrine/Migration/Builder.phpます。531行目に進みます。すべての移行が拡張するデフォルトのクラスの定義があります。CLIを使用していて、この場所にパラメーターを渡す方法が見つからなかったため、以下Doctrine_Migration_Baseの別のクラスMY_Doctrine_Migration_Baseに置き換えました。

CLIを使用していない場合は、ソースを置き換えるのではなく、オプションを渡すようにしてください。

したがって、以下のクラスはDoctrine_Migration_Base、一連のメソッドを拡張して上書きし、変更を加えてもよいかどうかを確認してから、親メソッドを呼び出して変更を行います。現在すべてのメソッドを網羅しているわけではなく、これを書いたときに遭遇したメソッドだけを網羅しています。

これで、Doctrineが作成するすべての移行により、最初に述べた問題を防ぐことを目的としたクラスが拡張されます。

<?php

class MY_Doctrine_Migration_Base extends Doctrine_Migration_Base {
    public function __construct() {
        $this->connection = Doctrine_Manager::getInstance()->getCurrentConnection();
    }

    public function addIndex($tableName, $indexName, array $definition) {
        foreach ($this->connection->execute("SHOW INDEXES IN $tableName")->fetchAll(PDO::FETCH_ASSOC) as $index) {
            if ($index['Key_name'] === $indexName.'_idx') {
                echo "Index $indexName already exists in table $tableName. Skipping\n";
                return;
            }
        }

        parent::addIndex($tableName, $indexName, $definition);
    }

    public function removeColumn($tableName, $columnName) {
        if ($this->column_exists($tableName, $columnName)) {
            parent::removeColumn($tableName, $columnName);
        } else {
            echo "Column $columnName doesn't exist in $tableName. Can't drop\n";
        }
    }

    public function createTable($tableName, array $fields = array(), array $options = array()) {
        if ($this->connection->execute("SHOW TABLES LIKE '$tableName'")->fetchAll(PDO::FETCH_ASSOC)) {
            echo "Table $tableName already exists. Can't create\n";
        } else {
            parent::createTable($tableName, $fields, $options);
        }
    }

    public function addColumn($tableName, $columnName, $type, $length = null, array $options = array()) {
        if (! $this->column_exists($tableName, $columnName)) {
            parent::addColumn($tableName, $columnName, $type, $length, $options);
        } else {
            echo "Column $columnName already exists in $tableName. Can't add\n";
        }
    }

    private function column_exists($tableName, $columnName) {
        $exception = FALSE;

        try { //parsing information_schema sucks because security will hurt too bad if we have access to it. This lame shit is still better
            $this->connection->execute("SELECT $columnName FROM $tableName")->fetchAll(PDO::FETCH_ASSOC);
        } catch (Exception $exception) {}
        //if someone knows how to check for column existence without exceptions AND WITHOUT INFORMATION SCHEMA please rewrite this stuff

        return $exception === FALSE;
    }
}

これを改善する方法についての提案を歓迎します。

于 2011-02-08T16:15:37.733 に答える
1

doctrine-cliを使用している場合は、移行前にデータベースをバックアップし、移行が失敗した場合にバックアップを復元する独自の移行タスクを作成できます。symfony/doctrineの移行についても同様のことを書きました。

タスククラスを正しいディレクトリに配置すると、doctrinecliは使用可能なコマンドのリストにタスククラスを表示します

于 2011-02-03T09:06:20.980 に答える
0

教義の移行はこれを処理できません。移行がトランザクションで実行されなかったため、私たち全員がこれらの問題を抱えていると言って申し訳ありません。

プラグインを追加することでこれを改善できます。参照:ブログ投稿

もう1つの可能性は、移行する前にデータベースのバックアップを実行することです。問題が発生した場合は、バックアップを再インストールできます。シェルスクリプトでこれを自動化できます

于 2011-01-19T07:57:57.760 に答える