[DDC-2245] EntityManager#getReference returns NULL on SINGLE_TABLE inheritance Created: 15/Jan/13  Updated: 20/Jan/13  Resolved: 20/Jan/13

Status: Resolved
Project: Doctrine 2 - ORM
Component/s: ORM
Affects Version/s: 2.3.2
Fix Version/s: None

Type: Bug Priority: Major
Reporter: Masaki Fujimoto Assignee: Benjamin Eberlei
Resolution: Invalid Votes: 0
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.



 Comments   
Comment by Marco Pivetta [ 15/Jan/13 ]

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

Do you have any example code for this?

Comment by Masaki Fujimoto [ 15/Jan/13 ]

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

Comment by Benjamin Eberlei [ 20/Jan/13 ]

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.

Comment by Masaki Fujimoto [ 20/Jan/13 ]

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.

Comment by Marco Pivetta [ 20/Jan/13 ]

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

Comment by Masaki Fujimoto [ 20/Jan/13 ]

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?

Comment by Marco Pivetta [ 20/Jan/13 ]

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.

Comment by Masaki Fujimoto [ 20/Jan/13 ]

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

Generated at Sat Oct 25 20:12:21 UTC 2014 using JIRA 6.2.3#6260-sha1:63ef1d6dac3f4f4d7db4c1effd405ba38ccdc558.