Импорт таблиц из внешней базы данных в Symfony2 с помощью доктрины - PullRequest
23 голосов
/ 01 июля 2011

У меня есть проект 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 доктрина: mapping: import --em = buv --filter = "tablename" MyBundle yml

Но я получаю ту же ошибку, похоже, что --filter не работает.

Документация в доктрине консольной команды: mapping: import говорит только о том, чтобы поместить имя сущности вопция фильтра.Но у меня пока нет сущности.

Ответы [ 8 ]

15 голосов
/ 02 апреля 2013

Для Doctrine требуется, чтобы имел идентификатор / первичный ключ .Взгляните на эту страницу: http://www.doctrine -project.org / docs / orm / 2.0 / en / reference / basic-mapping.html # идентификаторы-первичные ключи

Но есть - это способ создания сопоставлений и сущностей из таблиц, которые не имеют первичного ключа .Таблица без первичного ключа - это необычный и плохой дизайн базы данных, но такой сценарий существует в случае устаревших баз данных.

Решение : Примечание : Все ссылки ниже относятся к Доктрине 2.01. Найдите файл 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 / annotation) даже для таблиц, у которых нет первичного ключа.

15 голосов
/ 03 ноября 2011

Если я правильно понимаю, вы хотите импортировать существующую базу данных?

Что я делаю:

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 будет удален ваш текущий файл сущности.

4 голосов
/ 28 июля 2016

Я успешно импортировал некоторые объекты базы данных, добавив schema_filter в конфигурацию 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 doctrine:mapping:import --force MyBundle yml

Затем верните config.yml.

3 голосов
/ 07 сентября 2016

Обратите внимание, что --filter в вашей команде должно быть заполнено именем Entity Class , а не Table name.Если объект еще не существует, имя класса объекта должно дополнять имя вашей таблицы.Поэтому, если ваша таблица равна 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)$/');
3 голосов
/ 20 сентября 2014

Я создал решение на основе всех комментариев, которое упрощает код

для пространства имен класса 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();

Чтобы избежать проблем в будущем, после сопоставлениябазы данных, верните настройки, чтобы избежать проблем позже.Удачи!

1 голос
/ 19 декабря 2013

Вы должны обновить функцию 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();
}
0 голосов
/ 12 сентября 2018

В файле 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'));
0 голосов
/ 18 августа 2017
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
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...