【问题标题】:doctrine migrations bundle and postgres schema: diff does not work properly学说迁移捆绑包和 postgres 架构:差异无法正常工作
【发布时间】:2023-03-06 17:27:01
【问题描述】:

我在我的 Symfony 项目中使用 doctrine,通过连接到已经存在的 postgres 数据库。

数据库有几个模式,但 symfony 应用程序只使用它自己的模式。我创建的第一个Entity 类如下:

namespace Belka\TestBundle\Entity;

use Doctrine\ORM\Mapping as ORM;

/**
 * @ORM\Entity
 * @ORM\Table(name="app_auth.User", schema="app_auth")
 */
class User {
    /**
     * @ORM\Column(type="string")
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="NONE")
     */
    private $username;

    /**
     * @ORM\Column(type="string")
     */
    private $email;

    /**
     * @ORM\Column(type="string")
     */
    private $password;
}

如您所见,Entity 指定了自己的架构app_auth。 接下来,我尝试使用迁移包。因此,我安装并配置了它,以便只考虑我的架构:

config.yml 的摘录:

doctrine:
    dbal:
        driver:   "%database_driver%"
        host:     "%database_host%"
        port:     "%database_port%"
        dbname:   "%database_name%"
        user:     "%database_user%"
        password: "%database_password%"
        charset:  UTF8
        schema_filter: ~^app_auth\..*~

config_dev.yml 的摘录:

doctrine_migrations:
    dir_name: "%kernel.root_dir%/../.container/update/DoctrineMigrations"
    namespace: Application\Migrations
    table_name: "app_auth.migration_versions"
    name: Application Migrations

然后我运行 diff:

php app/console doctrine:migrations:diff

很遗憾,生成的迁移类如下:

namespace Application\Migrations;

use Doctrine\DBAL\Migrations\AbstractMigration;
use Doctrine\DBAL\Schema\Schema;

/**
 * Auto-generated Migration: Please modify to your needs!
 */
class Version20160422171409 extends AbstractMigration
{
    /**
     * @param Schema $schema
     */
    public function up(Schema $schema)
    {
        // this up() migration is auto-generated, please modify it to your needs

    }

    /**
     * @param Schema $schema
     */
    public function down(Schema $schema)
    {
        // this down() migration is auto-generated, please modify it to your needs
        $this->abortIf($this->connection->getDatabasePlatform()->getName() != 'postgresql', 'Migration can only be executed safely on \'postgresql\'.');

        $this->addSql('CREATE SCHEMA app_auth');
    }
}

那我的配置有什么问题?

【问题讨论】:

  • 您看到的是哪个错误消息?
  • 我没有收到任何错误。它实际上似乎忽略了实体。我自己创建了表格并再次运行migrations:diff:我得到的是一个空的up 和一个带有DROP 表格的down
  • @Bertuz 我面临同样的问题。我知道您的帖子很旧,但是您找到解决方案了吗?
  • 不,如果我没记错的话,我是手工完成的。把它们写在 github 上怎么样?
  • 我仍然在发生这种情况。 Symfony 5.1。

标签: postgresql symfony doctrine-orm doctrine-migrations


【解决方案1】:

肮脏但有效的解决方案:

通过学说/迁移测试:3.0.1

我们可以修补 DiffGenerator 的模式删除功能。我个人用过这个https://github.com/cweagans/composer-patches

安装包,然后在composer.json的“extra”部分添加:

"patches": {
        "doctrine/migrations": {
            "Change doctrine behavior to correctly pass PostgreSQL schema to schema_filter while diffing": "patches/doctrine-diff-generator.patch"
        }
    }

patches/doctrine-diff-generator.patch 中的补丁文件:

--- lib/Doctrine/Migrations/Generator/DiffGenerator.php      2020-06-21 10:55:42.000000000 +0200
+++ lib/Doctrine/Migrations/Generator/DiffGenerator.patched.php      2020-12-23 12:33:02.689405221 +0100
@@ -142,8 +142,6 @@
  */
 private function resolveTableName(string $name) : string
     {
-        $pos = strpos($name, '.');
-
-        return $pos === false ? $name : substr($name, $pos + 1);
+        return $name;
     }
 }

当然,您必须记住,教义更新可能会破坏补丁。而且您正在为您的学说全局更改此功能,因此请注意破坏性更改。

就我个人而言,对于我的用例,即在不破坏旧数据库的情况下将理论实体添加到旧数据库中,这很好用,并且使我免于将每一个由理论管理的新表添加到 schema_filter 中。

解释: 当我们查看 DiffGenerator 实现时,它实际上使用模式正确解码表名,但仅在收集当前数据库模式时。这发生在 PostgreSqlSchemaManager.php 中:

    /**
 * {@inheritdoc}
 */
protected function _getPortableTableDefinition($table)
{
    $schemas     = $this->getExistingSchemaSearchPaths();
    $firstSchema = array_shift($schemas);

    if ($table['schema_name'] === $firstSchema) {
        return $table['table_name'];
    }

    return $table['schema_name'] . '.' . $table['table_name'];
}

但是随后在计算目标模式时,此信息在 DiffGenerator.php 中丢失了:

    /**
 * Resolve a table name from its fully qualified name. The `$name` argument
 * comes from Doctrine\DBAL\Schema\Table#getName which can sometimes return
 * a namespaced name with the form `{namespace}.{tableName}`. This extracts
 * the table name from that.
 */
private function resolveTableName(string $name) : string
{
    $pos = strpos($name, '.');

    return $pos === false ? $name : substr($name, $pos + 1);
}

只有在此之后,这个函数的返回值才会被传递到 schema_filter。不幸的是,但我想这是有原因的:)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-05-14
    • 1970-01-01
    • 1970-01-01
    • 2016-12-18
    • 2017-05-12
    • 2018-12-09
    相关资源
    最近更新 更多