使用 Doctrine2 和 PostgreSQL 进行多数据库模式和迁移

Posted

技术标签:

【中文标题】使用 Doctrine2 和 PostgreSQL 进行多数据库模式和迁移【英文标题】:Multiple DB Schema & migrations with Doctrine2 & PostgreSQL 【发布时间】:2015-12-29 16:22:11 【问题描述】:

我有一个包含多个模式的 PG 数据库。

我有一个 symfony2 应用程序,它只需要连接其中一个。

如果我没有配置任何东西,默认情况下,Doctrine2 会搜索所有模式,因此它会尝试在它不正确的表上创建 SELECT

我关注了这个答案:symfony2 + doctrine2@postgresql setting a schema

现在它似乎只出现在我指定的 shema 中,但它仍在寻找一些在我的架构中不存在但在其他架构中存在的表。

当我执行一些 ldoctrine:migrations:diff

[Doctrine\DBAL\DBALException]                                                                     
  An exception occurred while executing 'SELECT min_value, increment_by FROM "pgstatspacknameid"':  
  SQLSTATE[42P01]: Undefined table: 7 ERROR:  relation "pgstatspacknameid" does not exist           
  LINE 1: SELECT min_value, increment_by FROM "pgstatspacknameid"                                   
                                              ^                                                     

  [PDOException]                                                                           
  SQLSTATE[42P01]: Undefined table: 7 ERROR:  relation "pgstatspacknameid" does not exist  
  LINE 1: SELECT min_value, increment_by FROM "pgstatspacknameid"                          
                                              ^      

所以按照学说迁移文档,我在连接配置中添加了这一行:

        schema_filter: ~^(?!pgstats)~

它仍然总是尝试在那些表中创建SELECT...

【问题讨论】:

【参考方案1】:

迁移命令需要选项 --db-configuration。 它需要一个配置文件作为参数。 尝试使用配置文件的以下内容。

<?php
return array(
    "driverClass"=>"AppBundle\Driver",
    "host" => "localhost",
    "user" => "test",
    "password" => "test",
    "dbname" => "test"
        );
?>

此外,我更改了 vendor/doctrine/dbal/lib/Doctrine/DBAL/SchemaPostgreSqlSchemaManager.php 以始终将模式添加到序列名称之前。

像这样:

/**
 * @inheritdoc
 */
protected function _getPortableSequencesList($sequences)

    $sequenceDefinitions = array();
    foreach ($sequences as $sequence) //+ || true
        if ($sequence['schemaname'] != 'public' || true) 
            $sequenceName = $sequence['schemaname'] . "." . $sequence['relname'];
         else 
            $sequenceName = $sequence['relname'];
        

        $sequenceDefinitions[$sequenceName] = $sequence;
    
    $list = array();

    foreach ($this->filterAssetNames(array_keys($sequenceDefinitions)) as $sequenceName) 
        $list[] = $this->_getPortableSequenceDefinition($sequenceDefinitions[$sequenceName]);
    
    return $list;


/**
 * @inheritdoc
 */
protected function getPortableNamespaceDefinition(array $namespace)

    return $namespace['nspname'];


/**
 * @inheritdoc
 */
protected function _getPortableSequenceDefinition($sequence)
//+ || true
    if ($sequence['schemaname'] != 'public' || true) 
        $sequenceName = $sequence['schemaname'] . "." . $sequence['relname'];
     else 
        $sequenceName = $sequence['relname'];
    

    $data = $this->_conn->fetchAll('SELECT min_value, increment_by FROM ' . $this->_platform->quoteIdentifier($sequenceName));

    return new Sequence($sequenceName, $data[0]['increment_by'], $data[0]['min_value']);

(在假定架构名称 != 'public' 的地方添加了 or true 两个地方)

【讨论】:

谢谢我要测试这个解决方案!您知道如何在不更改 vendor 文件的情况下覆盖此类吗? 未测试,但您可以从 AbstractPostgresqlDriver 覆盖 getSchemaManager 以返回具有上述更改的自定义 SchemaManager。

以上是关于使用 Doctrine2 和 PostgreSQL 进行多数据库模式和迁移的主要内容,如果未能解决你的问题,请参考以下文章

如何使Doctrine PostgreSQL外键约束DEFERRABLE

Doctrine2:使用 NativeQuery 和 ResultSetMapping 进行查询

Doctrine2 - 一次多次插入

Doctrine2.2 (sqlite using memory) 使用 OrmTestCase 和 phpUnit TroubleShoot

Doctrine2:任意连接和单表继承

在 Doctrine2 查询中使用 Limit 和 Offset