Symfony Doctrine Models for Entity Without Primary Keys

前端 未结 2 1856
醉话见心
醉话见心 2021-01-14 09:10

I\'m working with a legacy database while re-building the web application. I want to use Symfony2.x which obviously has Doctrine as ORM.

I\'ve around 50 (mysql) tab

相关标签:
2条回答
  • 2021-01-14 09:49

    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.

    0 讨论(0)
  • 2021-01-14 09:52

    Doctrine requires every entity class 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

    0 讨论(0)
提交回复
热议问题