使用doctrine从Symfony2中的外部数据库导入表

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了使用doctrine从Symfony2中的外部数据库导入表相关的知识,希望对你有一定的参考价值。

我有一个带有自己的数据库的Symfony2项目,现在我想连接到另一个数据库(另一个项目),所以我可以修改一些表。

我在config_dev.yml中创建了新连接

doctrine:
    dbal:
        default_connection: default
        connections:
            default:
                driver:   pdo_mysql
                host:     localhost
                dbname:   database1
                user:     root
                password: 
            buv:
                driver:   pdo_mysql
                host:     localhost
                dbname:   database2
                user:     root
                password:

我尝试使用以下命令导入架构:

$ php app / console doctrine:mapping:import --em = buv MyBundle en

[Doctrine DBAL Schema SchemaException]表'old_table'上不存在索引''

但是database2中的一些表没有PK!并且完全导入不起作用。但我只想导入两个表,所以我试过:

$ php app / console doctrine:mapping:import --em = buv --filter =“tablename”MyBundle yml

但我得到了同样的错误,似乎--filter不工作。

控制台命令doctrine:mapping:import中的文档仅表示将实体名称放在过滤器选项中。但我还没有实体。

答案

如果我找到你,你想导入你现有的数据库?

我所做的是:

php app/console doctrine:mapping:convert xml ./src/App/MyBundle/Resources/config/doctrine/metadata/orm --from-database --force

然后选择性转换为注释:

php app/console doctrine:mapping:import AppMyBundle annotation --filter="users_table"

如果您想要yml,请将注释更改为yml。

警告:当您导入到注释或yml时,它将删除您当前的实体文件。

另一答案

Doctrine要求具有标识符/主键。看看这个页面:http://www.doctrine-project.org/docs/orm/2.0/en/reference/basic-mapping.html#identifiers-primary-keys

但是有一种方法可以从没有主键的表中生成映射和实体。没有主键的表是一种不寻常和错误的数据库设计,但在遗留数据库的情况下存在这种情况。

解: 注意:以下所有参考文献均参考Doctrine 2.0 1.找到文件DatabaseDriver.php(在Doctrine / ORM / Mapping / Driver / DatabaseDriver.php中) 2.找到reverseEngineerMappingFromDatabase方法。修改如下所述的代码。 原始代码是:

private function reverseEngineerMappingFromDatabase()
    {
        if ($this->tables !== null) {
            return;
        }

        $tables = array();

        foreach ($this->_sm->listTableNames() as $tableName) {
            $tables[$tableName] = $this->_sm->listTableDetails($tableName);
        }

        $this->tables = $this->manyToManyTables = $this->classToTableNames = array();
        foreach ($tables as $tableName => $table) {
            /* @var $table DoctrineDBALSchemaTable */
            if ($this->_sm->getDatabasePlatform()->supportsForeignKeyConstraints()) {
                $foreignKeys = $table->getForeignKeys();
            } else {
                $foreignKeys = array();
            }

            $allForeignKeyColumns = array();
            foreach ($foreignKeys as $foreignKey) {
                $allForeignKeyColumns = array_merge($allForeignKeyColumns, $foreignKey->getLocalColumns());
            }

            if ( ! $table->hasPrimaryKey()) {
                throw new MappingException(
                    "Table " . $table->getName() . " has no primary key. Doctrine does not ".
                    "support reverse engineering from tables that don't have a primary key."
                );
            }

            $pkColumns = $table->getPrimaryKey()->getColumns();
            sort($pkColumns);
            sort($allForeignKeyColumns);

            if ($pkColumns == $allForeignKeyColumns && count($foreignKeys) == 2) {
                $this->manyToManyTables[$tableName] = $table;
            } else {
                // lower-casing is necessary because of Oracle Uppercase Tablenames,
                // assumption is lower-case + underscore separated.
                $className = $this->getClassNameForTable($tableName);
                $this->tables[$tableName] = $table;
                $this->classToTableNames[$className] = $tableName;
            }
        }
    }

修改后的代码是:

private function reverseEngineerMappingFromDatabase()
    {
        if ($this->tables !== null) {
            return;
        }

        $tables = array();

        foreach ($this->_sm->listTableNames() as $tableName) {
            $tables[$tableName] = $this->_sm->listTableDetails($tableName);
        }

        $this->tables = $this->manyToManyTables = $this->classToTableNames = array();
        foreach ($tables as $tableName => $table) {
            /* @var $table DoctrineDBALSchemaTable */
            if ($this->_sm->getDatabasePlatform()->supportsForeignKeyConstraints()) {
                $foreignKeys = $table->getForeignKeys();
            } else {
                $foreignKeys = array();
            }

            $allForeignKeyColumns = array();
            foreach ($foreignKeys as $foreignKey) {
                $allForeignKeyColumns = array_merge($allForeignKeyColumns, $foreignKey->getLocalColumns());
            }

            $pkColumns=array();
            if ($table->hasPrimaryKey()) {
                $pkColumns = $table->getPrimaryKey()->getColumns();
                sort($pkColumns);
            }

            sort($allForeignKeyColumns);

            if ($pkColumns == $allForeignKeyColumns && count($foreignKeys) == 2) {
                $this->manyToManyTables[$tableName] = $table;
            } else {
                // lower-casing is necessary because of Oracle Uppercase Tablenames,
                // assumption is lower-case + underscore separated.
                $className = $this->getClassNameForTable($tableName);
                $this->tables[$tableName] = $table;
                $this->classToTableNames[$className] = $tableName;
            }
        }
    }

3.在同一文件中找到方法loadMetadataForClass。修改如下所述的代码。 找到下面陈述的代码:

try {
   $primaryKeyColumns = $this->tables[$tableName]->getPrimaryKey()->getColumns();
} catch(SchemaException $e) {
    $primaryKeyColumns = array();
}

像这样修改它:

try {
     $primaryKeyColumns = ($this->tables[$tableName]->hasPrimaryKey())?$this->tables[$tableName]->getPrimaryKey()->getColumns():array();
} catch(SchemaException $e) {
     $primaryKeyColumns = array();
}

即使对于没有主键的表,上述解决方案也会创建映射(xml / yml / annotation)。

另一答案

通过在doctrine dbal config中添加schema_filter,我成功导入了一些数据库实体(~/app/config/config.yml

# Doctrine Configuration
doctrine:
    dbal:
        driver:   %database_driver%
        host:     %database_host%
        port:     %database_port%
        dbname:   %database_name%
        user:     %database_user%
        password: %database_password%
        charset:  UTF8
        schema_filter: /^users_table/

app/console doctrine:mapping:import --force MyBundle yml

然后还原config.yml。

另一答案

我基于简化代码的所有注释创建了一个解决方案

在类名称空间Doctrine ORM Mapping Driver; DatabaseDriver.php

在第277行,更改:

if (!$table->hasPrimaryKey()) {
      // comment this Throw exception
      // throw new MappingException(
      // “Table “ . $table->getName() . “ has no primary key.
      // Doctrine does not “.
      // “support reverse engineering from tables that don’t
      // have a primary key.”
      // );
} else {
     $pkColumns = $table->getPrimaryKey()->getColumns();
}

并且,在第488行,添加:

if( $table->hasPrimaryKey() ) //add this if to avoid fatalError
 return $table->getPrimaryKey()->getColumns();

为避免将来出现任何问题,请在映射数据库后返回设置以避免以后出现任何问题。祝好运!

另一答案

请注意,命令中的--filter应填充实体类名称而不是表名称。如果实体尚不存在,则实体类名称必须与您的表名称相符。因此,如果您的表是user_table,则过滤器值将为UserTable

然后,要解决您的数据库有一些Doctrine无法处理的表,您应该将您希望允许Doctrine管理的表列入白名单。您可以在配置文件中执行此操作,如下所示:

doctrine:
    dbal:
        # ... 
        schema_filter: /^(users_table|emails)$/

或者你可以在你的cli-config.php文件中指定它。

/** @var DoctrineORMConfiguration $config */
$config->setFilterSchemaAssetsExpression('/^(users_table|email)$/');
另一答案

您必须将getTablePrimaryKeys函数更新为:

private function getTablePrimaryKeys(Table $table)
{
    try {       
        $primaryKeyColumns = ($this->tables[$table->getName()]->hasPrimaryKey())?$this->tables[$table->getName()]->getPrimaryKey()->getColumns():array();
    } catch(SchemaException $e) {
        $primaryKeyColumns = array();
    }

    return array();
}
另一答案

在DatabaseDriver.php文件中,您可以更改reverseEngineerMappingFromDatabase函数

以上是关于使用doctrine从Symfony2中的外部数据库导入表的主要内容,如果未能解决你的问题,请参考以下文章

如何从 Symfony2 和 Doctrine2 中的一个点保存和检索纬度和经度

Symfony2 项目中的 Doctrine2 映射问题

在 Doctrine2/Symfony2 中的重复条目上插入忽略

带有 Symfony2 的 Doctrine2 无法识别数据库字符集和排序规则

使用 Symfony2 和 Doctrine 的 SQL Server 数据库连接

Symfony2,Doctrine,延迟加载和代理类问题