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

发布于 2024-11-17 22:58:52 字数 1076 浏览 2 评论 0原文

我有一个带有自己数据库的 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 yml

[Doctrine\DBAL\Schema\SchemaException] 表“old_table”上不存在索引“”

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

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

但我遇到了相同的错误,似乎 --filter 不起作用。

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

I have a Symfony2 project with its own database, and now I want to connect to another database (another project) so I can modify some tables.

I created the new connection in 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:

I tried to import the schema with the following command:

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

[Doctrine\DBAL\Schema\SchemaException]
Index '' does not exist on table 'old_table'

But some of the tables in database2 have no PKs! And the full import dosn't work. But I only want to import two tables, so I tried:

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

But I'm getting the same error, seems that --filter isn't working.

The documentation in the console command doctrine:mapping:import only says to put the entity name in the filter option. But I don't have an entity yet.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(9

鸵鸟症 2024-11-24 22:58:52

如果我没理解的话,您想导入现有的数据库吗?

我所做的是:

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 时,它将删除您当前的实体文件。

If I get you correctly, you want to import your existing database?

What I do is:

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

Then do a selective convert to annotation:

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

If you wanted to yml, change annotation to yml.

warning: when you import to annotation or yml, it will delete your current entity file.

热血少△年 2024-11-24 22:58:52

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 \Doctrine\DBAL\Schema\Table */
            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 \Doctrine\DBAL\Schema\Table */
            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/注释)。

It is a requirement for Doctrine to have an identifier/primary key.
Take a look at this page: http://www.doctrine-project.org/docs/orm/2.0/en/reference/basic-mapping.html#identifiers-primary-keys

But there is a way to generate mappings and entities from tables that do not have a primary key. A table with no primary key is an unusual and bad database design but such a scenario exists in case of legacy databases.

Solution:
Note: All references below refer to Doctrine 2.0
1. Find the file DatabaseDriver.php (in Doctrine/ORM/Mapping/Driver/DatabaseDriver.php)
2. Find the method reverseEngineerMappingFromDatabase. Modify the code as stated below.
The original code is:

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 \Doctrine\DBAL\Schema\Table */
            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;
            }
        }
    }

The modified code is:

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 \Doctrine\DBAL\Schema\Table */
            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. Find the method loadMetadataForClass in the same file. Modify the code as stated below.
Find the code stated below:

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

Modify it like this:

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

The above solution creates mappings(xml/yml/annotation) even for tables that don't have a primary key.

一刻暧昧 2024-11-24 22:58:52

我通过在 dbal 配置 (~/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 学说中添加 schema_filter 成功导入了一些数据库实体:映射:导入 --force MyBundle yml

然后恢复 config.yml。

I've successfully imported some database entities by adding a schema_filter in the doctrine dbal config (~/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

Then revert config.yml.

寒冷纷飞旳雪 2024-11-24 22:58:52

我根据所有注释创建了一个解决方案,简化了

类上的 代码
命名空间 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();

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

I created a solution based on all comments that simplifies the code

on class
namespace Doctrine\ORM\Mapping\Driver;
DatabaseDriver.php

On line 277, change:

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();
}

And, on line 488, add:

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

To avoid any future problems, after mapping your database, return the settings to avoid any problems later.
Good luck!

溇涏 2024-11-24 22:58:52

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

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

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

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

/** @var Doctrine\ORM\Configuration $config */
$config->setFilterSchemaAssetsExpression('/^(users_table|email)$/');

Note that --filter in your command should be populated with the Entity Class name and not the Table name. If the entity does not yet exists, the Entity Class name must compliment your table name. So if your table is user_table, the filter value would be UserTable.

And then to work around that your DB has some tables that Doctrine cannot handle, you should whitelist the tables you do want allow Doctrine to manage. You can do this in your config file like, so:

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

alternatively you can specify this in your cli-config.php file.

/** @var Doctrine\ORM\Configuration $config */
$config->setFilterSchemaAssetsExpression('/^(users_table|email)$/');
红尘作伴 2024-11-24 22:58:52

您必须将 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();
}

You have to update the getTablePrimaryKeys function to:

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();
}
徒留西风 2024-11-24 22:58:52

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

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.");

更改

if(! $table->hasColumn('id')){
   $table->addColumn('id', 'integer', array('autoincrement' => true));
}
   $table->setPrimaryKey(array('id'));

At the DatabaseDriver.php file reverseEngineerMappingFromDatabase function you can change

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.");

with

if(! $table->hasColumn('id')){
   $table->addColumn('id', 'integer', array('autoincrement' => true));
}
   $table->setPrimaryKey(array('id'));
摘星┃星的人 2024-11-24 22:58:52

尝试至少暂时更改您的学说配置

doctrine:
    dbal:
        schema_filter: ~^(?!table1|table2)~

并运行:

php bin/console doctrine:mapping:convert --force --from-database --filter="CamelCasedTableName" --namespace="App\Entity\\" annotation   .

花了很多时间寻找这个解决方案。
考特尼·迈尔斯的奇怪但较高的答案对我不起作用。这个至少在 symfony 4.4 上工作得很好

Try at least temporary change your doctrine config

doctrine:
    dbal:
        schema_filter: ~^(?!table1|table2)~

And run:

php bin/console doctrine:mapping:convert --force --from-database --filter="CamelCasedTableName" --namespace="App\Entity\\" annotation   .

Spent a lot of hours finding this solution.
Stange but upper answer by Courtney Miles didn't work for me. And this one works fine at least on symfony 4.4

入画浅相思 2024-11-24 22:58:52
php bin/console doctrine:mapping:convert xml ./src/NameBundle/Resources/doctrine/metadata/orm

php bin/console doctrine:mapping:import NameBundle yml

php bin/console doctrine:generate:entities NameBundle
php bin/console doctrine:mapping:convert xml ./src/NameBundle/Resources/doctrine/metadata/orm

php bin/console doctrine:mapping:import NameBundle yml

php bin/console doctrine:generate:entities NameBundle
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文