2011-07-01 11 views
22

Mam projekt Symfony2 z własną bazą danych, a teraz chcę połączyć się z inną bazą danych (innym projektem), dzięki czemu mogę zmodyfikować niektóre tabele.Importowanie tabel z zewnętrznej bazy danych w Symfony2 przy użyciu doktryny

stworzyłem nowe połączenie w 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: 

Próbowałem zaimportować schemat za pomocą następującego polecenia:

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

[Doctrine \ DBAL \ Schema \ SchemaException] Index '' nie istnieje w tabeli 'old_table'

Ale niektóre tabele w bazie danych2 nie mają PKs! A pełny import nie działa. Ale ja tylko chce importować dwie tabele, więc próbowałem:

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

ale Otrzymuję ten sam błąd, wydaje się, że - filtr nie działa.

Dokumentacja w doktrynie polecenia konsoli: mapowanie: tylko import mówi, aby umieścić nazwę encji w opcji filtra. Ale nie mam jeszcze podmiotu.

Odpowiedz

12

Jeśli dostaję cię poprawnie, chcesz zaimportować istniejącą bazę danych?

Co mogę zrobić, to:

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

Następnie zrobić selektywną nawróconego do adnotacji:

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

Jeśli chciał yml, zmiany adnotacji do yml.

uwaga: po zaimportowaniu do adnotacji lub yml usunie on bieżący plik encji.

+4

Mam ten sam problem, pierwsze polecenie proponujesz nie wydają się działać, ponieważ jeden z moich tabelach nie ma PK. Jak to rozwiązuje? –

+0

Spróbuj wpisać argument filtru w przypadku wielbłąda, zaczynając od dużej litery, tj .: php app/console doktryna: mapowanie: import AppMyBundle yml --filter = "UsersTable" – ezpn

+1

Kiedy mam ten problem, filtr nie wydaje się być stosowane. Nie mogę jeszcze tego rozwiązać. – hugofcampos

15

Wymagane jest, aby Doctrine miała mieć identyfikator/klucz podstawowy. Spójrz na tej stronie: http://www.doctrine-project.org/docs/orm/2.0/en/reference/basic-mapping.html#identifiers-primary-keys

Ale jest sposobem generowania mapowania i podmioty z tabel, które nie mają klucz podstawowy. Tabela bez klucza podstawowego to nietypowy i zły projekt bazy danych, ale taki scenariusz istnieje w przypadku starszych baz danych.

Rozwiązanie:
Uwaga: Wszystkie odnośniki poniżej odnoszą się do doktryny 2.0
1. Znajdź plik DatabaseDriver.php (w doktrynie/ORM/Mapowanie/Kierowca/DatabaseDriver.php)
2 Znajdź metodę reverseEngineerMappingFromDatabase. Zmodyfikuj kod zgodnie z poniższym opisem.
Oryginalny kod jest:

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


Zmodyfikowany kod jest:

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. Znajdź metodę loadMetadataForClass w tym samym pliku. Zmodyfikuj kod zgodnie z poniższym opisem.
znaleźć kod nizej:

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


zmodyfikować go tak:

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



Powyższe rozwiązanie stwarza odwzorowań (XML/yml/adnotacji) nawet dla tabel, które don nie mają klucza głównego.

+0

im mój plik nie ma takiej linii, które występują u ma wzmianki w 'metody loadMetadataForClass' – Hunt

+1

Dotyczy to wersji 2.x –

+0

doktryna' prywatne getTablePrimaryKeys funkcyjne (tablica $ tabela) { try { $ primaryKeyColumns = ($ this -> tabele [$ table-> getName()] -> hasPrimaryKey())? $ this-> tables [$ table-> getName()] -> getPrimaryKey() -> getColumns(): array(); } catch (SchemaException $ e) { $ primaryKeyColumns = array(); } Zwróć tablicę(); } ' – bstricks

1

Musisz zaktualizować funkcję getTablePrimaryKeys do:

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

I stworzył rozwiązanie oparte na wszystkie komentarze, które upraszcza kod

od klasy nazw Doktryna \ ORM \ Mapowanie \ driver; DatabaseDriver.php

Na linii 277, zmiana:

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

A na linii 488, dodać:

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

Aby uniknąć problemów w przyszłości, po mapowanie bazy danych, przywrócić ustawienia aby uniknąć późniejszych problemów. Powodzenia!

+1

Przepraszamy za komentarze na temat starego posta, ale wpadłem na ten problem dziś wieczorem i dla mnie to rozwiązanie rzuciło wyjątek, więc dodałem '$ pkColumns = array();' w warunku 'if' i nie musiałem dodaj część do linii 488. Dziękuję bardzo. – gabtzi

+0

Aktualizacja dla Doctrine 2.5.5: pierwsza zmiana jest teraz w linii 287 (funkcja 'reverseEngineerMappingFromDatabase()'), a druga zmiana jest w linii 507 (funkcja 'getTablePrimaryKeys()') – Shady

4

mam zaimportowany niektóre podmioty bazy danych przez dodanie schema_filter w config doktryna 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

Następnie powróci config.yml.

+0

To zadziałało dla mnie. Dzięki! – Jotaeme

+0

'schema_filter' działa dobrze na Oracle db, dziękuję –

+0

Dzięki! Działa poprawnie na DB PostgreSQL – Xander

3

Zauważ, że --filter w poleceniu powinna być wypełniona Entity Class nazwy, a nie Tabela nazwy. Jeśli obiekt jeszcze nie istnieje, nazwa klasy musi uzupełniać nazwę tabeli. Jeśli więc Twoja tabela ma wartość user_table, wartość filtru będzie wynosić UserTable.

A następnie, aby obejść, że twój DB ma kilka tabel, których Doctrine nie może obsłużyć, powinieneś umieścić na białej liście tabele, które chcesz, aby umożliwić Doctrine zarządzanie. Można to zrobić w pliku konfiguracyjnym podobnego tak:

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

alternatywnie można określić to w pliku CLI-config.php.

/** @var Doctrine\ORM\Configuration $config */ 
$config->setFilterSchemaAssetsExpression('/^(users_table|email)$/'); 
0
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 
Powiązane problemy