Doctrine 2 - ORM
  1. Doctrine 2 - ORM
  2. DDC-2245

EntityManager#getReference returns NULL on SINGLE_TABLE inheritance

    Details

    • Type: Bug Bug
    • Status: Resolved
    • Priority: Major Major
    • Resolution: Invalid
    • Affects Version/s: 2.3.2
    • Fix Version/s: None
    • Component/s: ORM
    • Labels:
      None

      Description

      When EntityManager#getReference is called with SINGLE_TABLE inherited entity, it tries to get a loaded entity by calling unitOfWork->tryGetById($sortedId, $class->rootEntityName). The call may return an entity object of root entity class which is not what is asked, then it ends up returning NULL instead of going further.

        Activity

        Masaki Fujimoto created issue -
        Hide
        Marco Pivetta added a comment -

        This looks quite serious. On the other side, `getReference` should probably call `find` on inheritances.

        Do you have any example code for this?

        Show
        Marco Pivetta added a comment - This looks quite serious. On the other side, `getReference` should probably call `find` on inheritances. Do you have any example code for this?
        Hide
        Masaki Fujimoto added a comment - - edited

        Yes, following line returns NULL with entity classes I have(it's a part of Symfony2 project):

        $entity = $em->getRepository('EnjoitechBaseBundle:MCode')->find('01') // load an entity of root entity class
        $ref = $em->getReference('Enjoitech\BaseBundle\Entity\MCodeModule', '01'); // try to get reference of sub entity with same ID, this return NULL
        
        // $ref => NULL
        
        
        // MCode.php
        <?php
        
        namespace Enjoitech\BaseBundle\Entity;
        
        use \PDO;
        use Doctrine\ORM\Mapping as ORM;
        
        /**
         * @ORM\Entity
         * @ORM\Table(name="M_CODE")
         * @ORM\InheritanceType("SINGLE_TABLE")
         * @ORM\DiscriminatorColumn(name="CLASS", type="string", length=2)
         * @ORM\DiscriminatorMap({"00" = "MCode", "01" = "MCodeModule"})
         */
        class MCode
        {
            /**
             * @ORM\Id
             * @ORM\Column(type="string", length=2)
             */
            protected $CODE;
        
            /**
             * @ORM\Column(type="string", length=128)
             */
            protected $DESCRIPTION;
        
            public function getCODE()
            {
                return $this->CODE;
            }
        }
        
        
        /**
         * @ORM\Entity
         */
        class MCodeModule extends MCode
        {
        }
        

        I also saw a post that mentioned a similar/same issue at https://groups.google.com/forum/#!msg/doctrine-user/55IkFJlADh8/79QpCIH1Ag4J

        Show
        Masaki Fujimoto added a comment - - edited Yes, following line returns NULL with entity classes I have(it's a part of Symfony2 project): $entity = $em->getRepository('EnjoitechBaseBundle:MCode')->find('01') // load an entity of root entity class $ref = $em->getReference('Enjoitech\BaseBundle\Entity\MCodeModule', '01'); // try to get reference of sub entity with same ID, this return NULL // $ref => NULL // MCode.php <?php namespace Enjoitech\BaseBundle\Entity; use \PDO; use Doctrine\ORM\Mapping as ORM; /** * @ORM\Entity * @ORM\Table(name= "M_CODE" ) * @ORM\InheritanceType( "SINGLE_TABLE" ) * @ORM\DiscriminatorColumn(name= "CLASS" , type= "string" , length=2) * @ORM\DiscriminatorMap({ "00" = "MCode" , "01" = "MCodeModule" }) */ class MCode { /** * @ORM\Id * @ORM\Column(type= "string" , length=2) */ protected $CODE; /** * @ORM\Column(type= "string" , length=128) */ protected $DESCRIPTION; public function getCODE() { return $ this ->CODE; } } /** * @ORM\Entity */ class MCodeModule extends MCode { } I also saw a post that mentioned a similar/same issue at https://groups.google.com/forum/#!msg/doctrine-user/55IkFJlADh8/79QpCIH1Ag4J
        Hide
        Benjamin Eberlei added a comment -

        This is the correct behavior, if you fetch MCodeModule and its "only" a MCode, then returning null is correct, because you assume to retrieve a MCodeModule or nothing.

        Show
        Benjamin Eberlei added a comment - This is the correct behavior, if you fetch MCodeModule and its "only" a MCode, then returning null is correct, because you assume to retrieve a MCodeModule or nothing.
        Benjamin Eberlei made changes -
        Field Original Value New Value
        Status Open [ 1 ] Resolved [ 5 ]
        Resolution Invalid [ 6 ]
        Hide
        Masaki Fujimoto added a comment -

        I am not assuming getReference is supposed to fetch/retrieve/load anything. Shouldn't it return a reference to an entity object even the target entity hasn't been loaded yet? getReference won't return null because you'll never know if the entity exists in database in my opinion.

        Show
        Masaki Fujimoto added a comment - I am not assuming getReference is supposed to fetch/retrieve/load anything. Shouldn't it return a reference to an entity object even the target entity hasn't been loaded yet? getReference won't return null because you'll never know if the entity exists in database in my opinion.
        Hide
        Marco Pivetta added a comment -

        Masaki Fujimoto that doesn't work with inheritances, since you will need to query the discriminator column to know what object to instantiate

        Show
        Marco Pivetta added a comment - Masaki Fujimoto that doesn't work with inheritances, since you will need to query the discriminator column to know what object to instantiate
        Hide
        Masaki Fujimoto added a comment -

        I see, thanks for clarifying that. That was what I thought as far as I see in code; $sortedId array doesn't include discriminator column and value at all. So basically getReference won't guarantee its behaviour when the target is inheritances correct? I should rather use find() maybe. Will you keep that policy for future?

        I also encountered few more issues related to SINGLE_TABLE inheritance. something like find() returns entities of other inheritance class that were loaded earlier. I needed to clear entityManager each time before I get entities of another subclassed of MCode. I guess there may be same sort of implementation without considering discriminator column. Are these all known issues or it's just how it is intended?

        Show
        Masaki Fujimoto added a comment - I see, thanks for clarifying that. That was what I thought as far as I see in code; $sortedId array doesn't include discriminator column and value at all. So basically getReference won't guarantee its behaviour when the target is inheritances correct? I should rather use find() maybe. Will you keep that policy for future? I also encountered few more issues related to SINGLE_TABLE inheritance. something like find() returns entities of other inheritance class that were loaded earlier. I needed to clear entityManager each time before I get entities of another subclassed of MCode. I guess there may be same sort of implementation without considering discriminator column. Are these all known issues or it's just how it is intended?
        Hide
        Marco Pivetta added a comment -

        Masaki Fujimoto repeated calls to `find` give you the same instances for same identifiers. If you changed something, you'll need to `clear`, though it looks like you're doing a lot of unconventional stuff in there.

        I think that on STI/JTI, `getReference` could short-circuit to `find`, not sure if we want it.

        Show
        Marco Pivetta added a comment - Masaki Fujimoto repeated calls to `find` give you the same instances for same identifiers. If you changed something, you'll need to `clear`, though it looks like you're doing a lot of unconventional stuff in there. I think that on STI/JTI, `getReference` could short-circuit to `find`, not sure if we want it.
        Hide
        Masaki Fujimoto added a comment -

        I have just one code table. PK is a combination of CLASS and CODE columns. I use CLASS column as discriminator, and CODE column is ID of each inheritance. value in CODE column won't be unique by itself in the table but I thought SINGLE_TABLE inheritance can cover that. If this structure is unconventional, I'll have to look for workaround. thanks for all your help

        Show
        Masaki Fujimoto added a comment - I have just one code table. PK is a combination of CLASS and CODE columns. I use CLASS column as discriminator, and CODE column is ID of each inheritance. value in CODE column won't be unique by itself in the table but I thought SINGLE_TABLE inheritance can cover that. If this structure is unconventional, I'll have to look for workaround. thanks for all your help

        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-2245, expand=changesets[0:20].revisions[0:29],reviews}, methodType=GET}] : Received status code 503 (Service Temporarily Unavailable)

          People

          • Assignee:
            Benjamin Eberlei
            Reporter:
            Masaki Fujimoto
          • Votes:
            0 Vote for this issue
            Watchers:
            3 Start watching this issue

            Dates

            • Created:
              Updated:
              Resolved: