【问题标题】:Doctrine migrations fallback教义迁移后备
【发布时间】:2011-01-17 10:43:34
【问题描述】:

我们正在使用条令迁移,当迁移包含多个操作并且其中一个操作失败时,通常会出现问题。

例如,如果迁移添加了 5 个外键,并且其中第 5 个外键失败,而字段长度不同,则修复字段错误并重新生成迁移并修复整个事情,虽然现在有一个与密钥 4 已经存在并且不允许迁移成功运行的事实有关的错误。

有没有一种稳定的方法来使用 Doctrine 迁移而不会出现上述明显问题?我们以前使用过.sql 文件,实际上并没有好多少,但我很确定对于使用 Doctrine 的项目有正确的数据库版本控制方式吗?

根据模型和架构之间的差异生成迁移非常棒,我想进一步保留这种可能性。

谢谢

【问题讨论】:

    标签: php mysql migration doctrine database-versioning


    【解决方案1】:

    我有点解决了这个问题,这个解决方案并不是那么好,但我想它仍然对其他人有用。我正在使用 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;
        }
    }
    

    欢迎提出如何改进的建议。

    【讨论】:

      【解决方案2】:

      如果您使用的是教义-cli,您可以编写自己的迁移任务,在迁移之前备份数据库并在迁移失败时恢复备份。我为我们的 symfony/doctrine 迁移写了类似的东西。

      如果您将任务类放在正确的目录中,则学说 cli 会将其显示在可用命令列表中

      【讨论】:

        【解决方案3】:

        教义迁移无法处理这个问题。很抱歉,我们都有这些问题,因为迁移不是在事务中运行的。

        您可以通过添加插件来改善这一点。见:Blog-Post

        另一种可能性是在迁移之前进行数据库备份,如果出现问题,您可以重新安装备份。您可以通过 shell 脚本自动执行此操作

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2011-05-19
          • 1970-01-01
          • 1970-01-01
          • 2021-08-30
          • 2015-12-25
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多