Импорт таблиц из внешней базы данных в 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 yml
[Учение\DBAL\Схемы\SchemaException] Индекс '' не существует в таблице 'old_table'
Но у некоторых таблиц в database2 нет PK! И полный импорт не работает. Но я хочу импортировать только две таблицы, поэтому я попытался:
$ php app/console doctrine:mapping:import --em=buv --filter="tablename" MyBundle yml
Но я получаю ту же ошибку, похоже, что --filter не работает.
В документации к консольной команде doctrine:mapping:import
говорится только о том, чтобы поместить имя объекта в опцию фильтра. Но у меня пока нет сущности.
Ответы
Ответ 1
Если я правильно вас понял, вы хотите импортировать существующую базу данных?
Что я делаю:
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 он удалит текущий файл сущности.
Ответ 2
Для 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/annotation) даже для таблиц, у которых нет первичного ключа.
Ответ 3
Я успешно импортировал некоторые объекты базы данных, добавив schema_filter
в доктрину 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
Затем верните config.yml.
Ответ 4
Я создал решение на основе всех комментариев, упрощающих код
в классе
пространство имен 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();
Чтобы избежать любых будущих проблем, после сопоставления базы данных верните настройки, чтобы избежать каких-либо проблем позже.
Удачи!
Ответ 5
Обратите внимание, что --filter
в вашей команде должно быть заполнено именем Entity Class, а не Таблица. Если объект еще не существует, имя класса Entity должно дополнять имя вашей таблицы. Поэтому, если ваша таблица 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)$/');
Ответ 6
Вам необходимо обновить функцию 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();
}
Ответ 7
В файле 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'));
Ответ 8
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