Skip to content

Loading…

DDC-1799: Doctrine's Reverse Engineering 1-n (one to many) association misunderstood as 1-1 (one to one) #2453

Closed
doctrinebot opened this Issue · 6 comments

2 participants

@doctrinebot

Jira issue originally created by user linuxatico:

I found an odd behaviour of Doctrine's reverse engineering process, just create two simple tables tied by a simple 1-n relationship, take a look at the snap of the folowing SQL code:

    SET @OLD*UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE*CHECKS=0;
    SET @OLD*FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY*CHECKS=0;
    SET @OLD*SQL_MODE=@@SQL_MODE, SQL*MODE='TRADITIONAL';

    DROP SCHEMA IF EXISTS `ACME` ;
    CREATE SCHEMA IF NOT EXISTS `ACME` DEFAULT CHARACTER SET latin1 COLLATE latin1*swedish*ci ;
    USE `ACME` ;

    -- -----------------------------------------------------
    -- Table `ACME`.`task`
    -- -----------------------------------------------------
    DROP TABLE IF EXISTS `ACME`.`task` ;

    CREATE  TABLE IF NOT EXISTS `ACME`.`task` (
      `id*task` INT UNSIGNED NOT NULL AUTO*INCREMENT ,
      `description` VARCHAR(45) NULL ,
      PRIMARY KEY (`id_task`) )
    ENGINE = InnoDB;


    -- -----------------------------------------------------
    -- Table `ACME`.`tag`
    -- -----------------------------------------------------
    DROP TABLE IF EXISTS `ACME`.`tag` ;

    CREATE  TABLE IF NOT EXISTS `ACME`.`tag` (
      `id*tag` INT UNSIGNED NOT NULL AUTO*INCREMENT ,
      `name` VARCHAR(50) NULL ,
      `task_id` INT UNSIGNED NOT NULL ,
      PRIMARY KEY (`id_tag`) ,
      INDEX `fk*tag_task` (`task*id` ASC) ,
      CONSTRAINT `fk*tag*task`
        FOREIGN KEY (`task_id` )
        REFERENCES `ACME`.`task` (`id_task` )
        ON DELETE NO ACTION
        ON UPDATE NO ACTION)
    ENGINE = InnoDB;



    SET SQL*MODE=@OLD_SQL*MODE;
    SET FOREIGN*KEY_CHECKS=@OLD_FOREIGN_KEY*CHECKS;
    SET UNIQUE*CHECKS=@OLD_UNIQUE*CHECKS;

I have a Symfony2 netbeans project at

/Applications/MAMP/htdocs/Acme

and from that location, according to

http://symfony.com/doc/current/cookbook/doctrine/reverse_engineering.html

in a terminal I did:

    $ ./../../bin/php/php5.3.6/bin/php app/console doctrine:mapping:convert yml ./src/Acme/TaskBundle/Resources/config/doctrine/ --from-database --force
    Processing entity "Tag"
    Processing entity "Task"

    Exporting "yml" mapping information to "/Applications/MAMP/htdocs/Acme/src/Acme/TaskBundle/Resources/config/doctrine"

    $ ./../../bin/php/php5.3.6/bin/php app/console doctrine:mapping:import Acme\TaskBundle yml
    Importing mapping information from "default" entity manager
      > writing /Applications/MAMP/htdocs/Acme/src/Acme/TaskBundle/Resources/config/doctrine/Tag.orm.yml
      > writing /Applications/MAMP/htdocs/Acme/src/Acme/TaskBundle/Resources/config/doctrine/Task.orm.yml

    $ ./../../bin/php/php5.3.6/bin/php app/console doctrine:generate:entities Acme\TaskBundle
    Generating entities for bundle "AcmeTaskBundle"
      > backing up Tag.php to Tag.php<sub>
      > generating Acme\TaskBundle\Entity\Tag
      > backing up Task.php to Task.php</sub>
      > generating Acme\TaskBundle\Entity\Task

The fact is that it only seems ok, because if you take a look at "Tag.orm.yml":

    Acme\TaskBundle\Entity\Tag:
      type: entity
      table: tag
      fields:
        idTag:
          id: true
          type: integer
          unsigned: false
          nullable: false
          column: id_tag
          generator:
            strategy: IDENTITY
        name:
          type: string
          length: 50
          fixed: false
          nullable: true
      oneToOne:
        task:
          targetEntity: Task
          cascade: {  }
          mappedBy: null
          inversedBy: null
          joinColumns:
            task_id:
              referencedColumnName: id_task
          orphanRemoval: false
      lifecycleCallbacks: {  }

It created a **oneToOne* relationship and not a oneToMany* !

If you need any more confirmation, here are *Task.php and Tag.php*:

*Task.php*

    <?php

    namespace Acme\TaskBundle\Entity;

    use Doctrine\ORM\Mapping as ORM;

    /****
     * Acme\TaskBundle\Entity\Task
     */
    class Task
    {
        /****
         * @var integer $idTask
         */
        private $idTask;

        /****
         * @var string $description
         */
        private $description;


        /****
         * Get idTask
         *
         * @return integer 
         */
        public function getIdTask()
        {
            return $this->idTask;
        }

        /****
         * Set description
         *
         * @param string $description
         */
        public function setDescription($description)
        {
            $this->description = $description;
        }

        /****
         * Get description
         *
         * @return string 
         */
        public function getDescription()
        {
            return $this->description;
        }
    }
****Tag.php****

    <?php

    namespace Acme\TaskBundle\Entity;

    use Doctrine\ORM\Mapping as ORM;

    /****
     * Acme\TaskBundle\Entity\Tag
     */
    class Tag
    {
        /****
         * @var integer $idTag
         */
        private $idTag;

        /****
         * @var string $name
         */
        private $name;

        /****
         * @var Acme\TaskBundle\Entity\Task
         */
        private $task;


        /****
         * Get idTag
         *
         * @return integer 
         */
        public function getIdTag()
        {
            return $this->idTag;
        }

        /****
         * Set name
         *
         * @param string $name
         */
        public function setName($name)
        {
            $this->name = $name;
        }

        /****
         * Get name
         *
         * @return string 
         */
        public function getName()
        {
            return $this->name;
        }

        /****
         * Set task
         *
         * @param Acme\TaskBundle\Entity\Task $task
         */
        public function setTask(\Acme\TaskBundle\Entity\Task $task)
        {
            $this->task = $task;
        }

        /****
         * Get task
         *
         * @return Acme\TaskBundle\Entity\Task 
         */
        public function getTask()
        {
            return $this->task;
        }
    }

linuxatico

@doctrinebot

Comment created by linuxatico:

This problem is encountered only in this case, 1-1 and n-m relationship are handled in the right way, has anyone else faced this problem too?

linuxatico

@doctrinebot

Comment created by linuxatico:

Hi all,
I wanna give the Doctrine community my full support to help fixing this bug, but I need someone who can give me an answer.....
I couldn't figure out in the source code which is the method executed when given the command

$ ./../../bin/php/php5.3.6/bin/php app/console doctrine:mapping:convert yml ./src/Acme/TaskBundle/Resources/config/doctrine/ --from-database --force

I will keep on looking for it, but some help will be appreciated,

linuxatico

@doctrinebot

Comment created by linuxatico:

Found in vendor/doctrine/lib/Doctrine/ORM/Tools/Console/Command/ConvertMappingCommand.php
I'll see what I can do.

linuxatico

@doctrinebot

Comment created by linuxatico:

Even if I keep being ignored, I want to report a very useful discovery about this annoying bug: it's 100% related to the YAML conversion, because if you execute the first command

$ ./../../bin/php/php5.3.6/bin/php app/console doctrine:mapping:convert xml ./src/Acme/TaskBundle/Resources/config/doctrine/ --from-database --force

Using XML instead of YML it works in the expected way. I wonder if the author of this code have written a unit test before integrating this function in the official release of Doctrine.... (ironic question)

linuxatico

@doctrinebot

Comment created by @beberlei:

This case was indeed not unit-tested, many-to-one and one-to-one were handled the same in YAML Exporter. No need to get picky about it though, we are investing our free time here.

@doctrinebot

Issue was closed with resolution "Fixed"

@beberlei beberlei was assigned by doctrinebot
@doctrinebot doctrinebot added this to the 2.1.7 milestone
@doctrinebot doctrinebot closed this
@doctrinebot doctrinebot added the Bug label
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Something went wrong with that request. Please try again.