Doctrine 2 - ORM
  1. Doctrine 2 - ORM
  2. DDC-2383

Foreign relations on primary keys don't work on more than two entities (like Foo<>Bar<>Baz)

    Details

    • Type: Bug Bug
    • Status: Resolved
    • Priority: Major Major
    • Resolution: Can't Fix
    • Affects Version/s: 2.3, 2.4
    • Fix Version/s: None
    • Component/s: ORM

      Description

      I'm trying to accomplish something like this:
      http://docs.doctrine-project.org/en/latest/tutorials/composite-primary-keys.html#use-case-2-simple-derived-identity

      For two entities (Foo<>Bar) it works as expected but adding another entity related to Bar (so it's Foo<>Bar<>Baz) ends up with this error:

      Fatal error: Uncaught exception 'Doctrine\ORM\Mapping\MappingException' with message 'The column id must be mapped to a field in class Entity\Bar since it is referenced by a join column of another class.' in C:\...\vendor\doctrine\orm\lib\Doctrine\ORM\Mapping\MappingException.php:203
      Stack trace:
      #0 C:\...\vendor\doctrine\orm\lib\Doctrine\ORM\Persisters\BasicEntityPersister.php(734): Doctrine\ORM\Mapping\MappingException::joinColumnMustPointToMappedField('Entity\Bar', 'id')
      #1 C:\...\vendor\doctrine\orm\lib\Doctrine\ORM\UnitOfWork.php(2509): Doctrine\ORM\Persisters\BasicEntityPersister->loadOneToOneEntity(Array, Object(Entity\Bar))
      #2 C:\...\vendor\doctrine\orm\lib\Doctrine\ORM\Internal\Hydration\ObjectHydrator.php(245): Doctrine\ORM\UnitOfWork->createEntity('Entity\Bar', Array, Array)
      #3 C:\...\vendor\doctrine\orm\lib\Doctrine\ORM\Internal\Hydration\ObjectHydrator.php(424): Doctrine\ORM\Internal\Hydration\Ob in C:\...\vendor\doctrine\orm\lib\Doctrine\ORM\Mapping\MappingException.php on line 203
      

      This error appears when there are some records in the database and I want to query for example all Foos.

      My entites look like this:

      //Entity/Foo.php
      
      /** @Entity @Table(name="foos") */
      class Foo
      {
          /** @Id @Column(type="integer") @GeneratedValue */
          protected $id;
      
          /** @OneToOne(targetEntity="Bar", mappedBy="foo") */
          protected $bar;
      
          public function getId()
          {
              return $this->id;
          }
      
          public function getBar()
          {
              return $this->bar;
          }
      
          public function setBar($bar)
          {
              $bar->setFoo($this);
              $this->bar = $bar;
          }
      }
      
      //Entity/Bar.php
      
      /** @Entity @Table(name="bars") */
      class Bar
      {
          /** @Id @OneToOne(targetEntity="Foo", inversedBy="bar")
           * @JoinColumn(name="id", referencedColumnName="id") */
          protected $foo;
      
          /** @OneToOne(targetEntity="Baz", mappedBy="bar") */
          protected $baz;
      
          public function __construct($foo)
          {
              $this->foo = $foo;
          }
      
          public function getId()
          {
              return $this->getFoo()->getId();
          }
      
          public function getFoo()
          {
              return $this->foo;
          }
      
          public function setFoo($foo)
          {
              $this->foo = $foo;
          }
      
          public function getBaz()
          {
              return $this->baz;
          }
      
          public function setBaz($baz)
          {
              $bar->setBar($this);
              $this->baz = $baz;
          }
      }
      
      //Entity/Baz.php
      
      /** @Entity @Table(name="bazes") */
      class Baz
      {
          /** @Id @OneToOne(targetEntity="Bar", inversedBy="baz")
           * @JoinColumn(name="id", referencedColumnName="id") */
          protected $bar;
      
          public function __construct($bar)
          {
              $this->bar = $bar;
          }
      
          public function getId()
          {
              return $this->getBar()->getId();
          }
      
          public function getBar()
          {
              return $this->bar;
          }
      
          public function setBar($bar)
          {
              $this->bar = $bar;
          }
      }
      

      And fails on

      $fooRepository = $em->getRepository('Entity\Foo');
      $foos = $fooRepository->findAll();
      
      1. DDC2383Test.php
        3 kB
        Jacek Jędrzejewski

        Activity

        Jacek Jędrzejewski created issue -
        Jacek Jędrzejewski made changes -
        Field Original Value New Value
        Summary Foo<>Bar<>Baz - primary key and Foo<>Bar<>Baz - foreign relations on primary keys
        Jacek Jędrzejewski made changes -
        Description I'm trying to accomplish something like this:
        http://docs.doctrine-project.org/en/latest/tutorials/composite-primary-keys.html#use-case-2-simple-derived-identity

        For two entities (Foo<>Bar) it works as expected but adding another entity related to Bar (so it's Foo<>Bar<>Baz) ends up with this error:

        {code}
        [Doctrine\ORM\ORMException]
        Column name `id` referenced for relation from Entity\Baz towards Entity\Bar does not exist.
        {/code}

        My entites look like this:

        {code:php}
        //Entity/Foo.php

        /** @Entity @Table(name="foos") */
        class Foo
        {
            /** @Id @Column(type="integer") @GeneratedValue */
            protected $id;

            /** @OneToOne(targetEntity="Bar", mappedBy="foo") */
            protected $bar;

            public function getId()
            {
                return $this->id;
            }

            public function getBar()
            {
                return $this->bar;
            }

            public function setBar($bar)
            {
                $bar->setFoo($this);
                $this->bar = $bar;
            }
        }

        //Entity/Bar.php

        /** @Entity @Table(name="bars") */
        class Bar
        {
            /** @Id @OneToOne(targetEntity="Foo", inversedBy="bar") */
            protected $foo;

            /** @OneToOne(targetEntity="Baz", mappedBy="bar") */
            protected $baz;

            public function __construct($foo)
            {
                $this->foo = $foo;
            }

            public function getId()
            {
                return $this->getFoo()->getId();
            }

            public function getFoo()
            {
                return $this->foo;
            }

            public function setFoo($foo)
            {
                $this->foo = $foo;
            }

            public function getBaz()
            {
                return $this->baz;
            }

            public function setBaz($baz)
            {
                $bar->setBar($this);
                $this->baz = $baz;
            }
        }

        //Entity/Baz.php

        /** @Entity @Table(name="bazes") */
        class Baz
        {
            /** @Id @OneToOne(targetEntity="Bar", inversedBy="baz") */
            protected $bar;

            public function __construct($bar)
            {
                $this->bar = $bar;
            }

            public function getId()
            {
                return $this->getBar()->getId();
            }

            public function getBar()
            {
                return $this->bar;
            }

            public function setBar($bar)
            {
                $this->bar = $bar;
            }
        }
        {/code}
        I'm trying to accomplish something like this:
        http://docs.doctrine-project.org/en/latest/tutorials/composite-primary-keys.html#use-case-2-simple-derived-identity

        For two entities (Foo<>Bar) it works as expected but adding another entity related to Bar (so it's Foo<>Bar<>Baz) ends up with this error:

        {code}
        [Doctrine\ORM\ORMException]
        Column name `id` referenced for relation from Entity\Baz towards Entity\Bar does not exist.
        {code}

        My entites look like this:

        {code}
        //Entity/Foo.php

        /** @Entity @Table(name="foos") */
        class Foo
        {
            /** @Id @Column(type="integer") @GeneratedValue */
            protected $id;

            /** @OneToOne(targetEntity="Bar", mappedBy="foo") */
            protected $bar;

            public function getId()
            {
                return $this->id;
            }

            public function getBar()
            {
                return $this->bar;
            }

            public function setBar($bar)
            {
                $bar->setFoo($this);
                $this->bar = $bar;
            }
        }

        //Entity/Bar.php

        /** @Entity @Table(name="bars") */
        class Bar
        {
            /** @Id @OneToOne(targetEntity="Foo", inversedBy="bar") */
            protected $foo;

            /** @OneToOne(targetEntity="Baz", mappedBy="bar") */
            protected $baz;

            public function __construct($foo)
            {
                $this->foo = $foo;
            }

            public function getId()
            {
                return $this->getFoo()->getId();
            }

            public function getFoo()
            {
                return $this->foo;
            }

            public function setFoo($foo)
            {
                $this->foo = $foo;
            }

            public function getBaz()
            {
                return $this->baz;
            }

            public function setBaz($baz)
            {
                $bar->setBar($this);
                $this->baz = $baz;
            }
        }

        //Entity/Baz.php

        /** @Entity @Table(name="bazes") */
        class Baz
        {
            /** @Id @OneToOne(targetEntity="Bar", inversedBy="baz") */
            protected $bar;

            public function __construct($bar)
            {
                $this->bar = $bar;
            }

            public function getId()
            {
                return $this->getBar()->getId();
            }

            public function getBar()
            {
                return $this->bar;
            }

            public function setBar($bar)
            {
                $this->bar = $bar;
            }
        }
        {code}
        Jacek Jędrzejewski made changes -
        Summary Foo<>Bar<>Baz - foreign relations on primary keys Foreign relations on primary keys don't work on more than two entities (like Foo<>Bar<>Baz)
        Jacek Jędrzejewski made changes -
        Description I'm trying to accomplish something like this:
        http://docs.doctrine-project.org/en/latest/tutorials/composite-primary-keys.html#use-case-2-simple-derived-identity

        For two entities (Foo<>Bar) it works as expected but adding another entity related to Bar (so it's Foo<>Bar<>Baz) ends up with this error:

        {code}
        [Doctrine\ORM\ORMException]
        Column name `id` referenced for relation from Entity\Baz towards Entity\Bar does not exist.
        {code}

        My entites look like this:

        {code}
        //Entity/Foo.php

        /** @Entity @Table(name="foos") */
        class Foo
        {
            /** @Id @Column(type="integer") @GeneratedValue */
            protected $id;

            /** @OneToOne(targetEntity="Bar", mappedBy="foo") */
            protected $bar;

            public function getId()
            {
                return $this->id;
            }

            public function getBar()
            {
                return $this->bar;
            }

            public function setBar($bar)
            {
                $bar->setFoo($this);
                $this->bar = $bar;
            }
        }

        //Entity/Bar.php

        /** @Entity @Table(name="bars") */
        class Bar
        {
            /** @Id @OneToOne(targetEntity="Foo", inversedBy="bar") */
            protected $foo;

            /** @OneToOne(targetEntity="Baz", mappedBy="bar") */
            protected $baz;

            public function __construct($foo)
            {
                $this->foo = $foo;
            }

            public function getId()
            {
                return $this->getFoo()->getId();
            }

            public function getFoo()
            {
                return $this->foo;
            }

            public function setFoo($foo)
            {
                $this->foo = $foo;
            }

            public function getBaz()
            {
                return $this->baz;
            }

            public function setBaz($baz)
            {
                $bar->setBar($this);
                $this->baz = $baz;
            }
        }

        //Entity/Baz.php

        /** @Entity @Table(name="bazes") */
        class Baz
        {
            /** @Id @OneToOne(targetEntity="Bar", inversedBy="baz") */
            protected $bar;

            public function __construct($bar)
            {
                $this->bar = $bar;
            }

            public function getId()
            {
                return $this->getBar()->getId();
            }

            public function getBar()
            {
                return $this->bar;
            }

            public function setBar($bar)
            {
                $this->bar = $bar;
            }
        }
        {code}
        I'm trying to accomplish something like this:
        http://docs.doctrine-project.org/en/latest/tutorials/composite-primary-keys.html#use-case-2-simple-derived-identity

        For two entities (Foo<>Bar) it works as expected but adding another entity related to Bar (so it's Foo<>Bar<>Baz) ends up with this error:

        {code}
        Fatal error: Uncaught exception 'Doctrine\ORM\Mapping\MappingException' with message 'The column id must be mapped to a field in class Entity\Bar since it is referenced by a join column of another class.' in C:\...\vendor\doctrine\orm\lib\Doctrine\ORM\Mapping\MappingException.php:203
        Stack trace:
        #0 C:\...\vendor\doctrine\orm\lib\Doctrine\ORM\Persisters\BasicEntityPersister.php(734): Doctrine\ORM\Mapping\MappingException::joinColumnMustPointToMappedField('Entity\Bar', 'id')
        #1 C:\...\vendor\doctrine\orm\lib\Doctrine\ORM\UnitOfWork.php(2509): Doctrine\ORM\Persisters\BasicEntityPersister->loadOneToOneEntity(Array, Object(Entity\Bar))
        #2 C:\...\vendor\doctrine\orm\lib\Doctrine\ORM\Internal\Hydration\ObjectHydrator.php(245): Doctrine\ORM\UnitOfWork->createEntity('Entity\Bar', Array, Array)
        #3 C:\...\vendor\doctrine\orm\lib\Doctrine\ORM\Internal\Hydration\ObjectHydrator.php(424): Doctrine\ORM\Internal\Hydration\Ob in C:\...\vendor\doctrine\orm\lib\Doctrine\ORM\Mapping\MappingException.php on line 203
        {code}

        This error appears when there are some records in the database and I want to query for example all Foos.

        My entites look like this:

        {code}
        //Entity/Foo.php

        /** @Entity @Table(name="foos") */
        class Foo
        {
            /** @Id @Column(type="integer") @GeneratedValue */
            protected $id;

            /** @OneToOne(targetEntity="Bar", mappedBy="foo") */
            protected $bar;

            public function getId()
            {
                return $this->id;
            }

            public function getBar()
            {
                return $this->bar;
            }

            public function setBar($bar)
            {
                $bar->setFoo($this);
                $this->bar = $bar;
            }
        }

        //Entity/Bar.php

        /** @Entity @Table(name="bars") */
        class Bar
        {
            /** @Id @OneToOne(targetEntity="Foo", inversedBy="bar")
             * @JoinColumn(name="id", referencedColumnName="id") */
            protected $foo;

            /** @OneToOne(targetEntity="Baz", mappedBy="bar") */
            protected $baz;

            public function __construct($foo)
            {
                $this->foo = $foo;
            }

            public function getId()
            {
                return $this->getFoo()->getId();
            }

            public function getFoo()
            {
                return $this->foo;
            }

            public function setFoo($foo)
            {
                $this->foo = $foo;
            }

            public function getBaz()
            {
                return $this->baz;
            }

            public function setBaz($baz)
            {
                $bar->setBar($this);
                $this->baz = $baz;
            }
        }

        //Entity/Baz.php

        /** @Entity @Table(name="bazes") */
        class Baz
        {
            /** @Id @OneToOne(targetEntity="Bar", inversedBy="baz")
             * @JoinColumn(name="id", referencedColumnName="id") */
            protected $bar;

            public function __construct($bar)
            {
                $this->bar = $bar;
            }

            public function getId()
            {
                return $this->getBar()->getId();
            }

            public function getBar()
            {
                return $this->bar;
            }

            public function setBar($bar)
            {
                $this->bar = $bar;
            }
        }
        {code}

        And fails on

        {code}
        $fooRepository = $em->getRepository('Entity\Foo');
        $foos = $fooRepository->findAll();
        {code}
        Jacek Jędrzejewski made changes -
        Labels mapping relations hydration mapping relations
        Jacek Jędrzejewski made changes -
        Attachment DDC2383Test.php [ 11520 ]
        Hide
        Jacek Jędrzejewski added a comment -

        Attaching a test case which results in two exceptions - while creating the schema and while fetching entities.

        Show
        Jacek Jędrzejewski added a comment - Attaching a test case which results in two exceptions - while creating the schema and while fetching entities.
        Hide
        Benjamin Eberlei added a comment -

        This is sadly a restriction of the foreign keys as primary key feature.

        Due to the architecture of shared nothing Metadata instances we cannot validate this at mapping compile time, only at runtime, thus leading to this error.

        Show
        Benjamin Eberlei added a comment - This is sadly a restriction of the foreign keys as primary key feature. Due to the architecture of shared nothing Metadata instances we cannot validate this at mapping compile time, only at runtime, thus leading to this error.
        Benjamin Eberlei made changes -
        Status Open [ 1 ] Resolved [ 5 ]
        Resolution Can't Fix [ 7 ]

        This list may be incomplete, as errors occurred whilst retrieving source from linked applications:

        • Request to http://www.doctrine-project.org/fisheye/ failed: Error in remote call to 'FishEye 0 (http://www.doctrine-project.org/fisheye/)' (http://www.doctrine-project.org/fisheye) [AbstractRestCommand{path='/rest-service-fe/search-v1/crossRepositoryQuery', params={query=DDC-2383, expand=changesets[0:20].revisions[0:29],reviews}, methodType=GET}] : Received status code 503 (Service Temporarily Unavailable)

          People

          • Assignee:
            Benjamin Eberlei
            Reporter:
            Jacek Jędrzejewski
          • Votes:
            0 Vote for this issue
            Watchers:
            2 Start watching this issue

            Dates

            • Created:
              Updated:
              Resolved: