Three level table class inheritance not loading second level data due to wrong query generation #6458

Closed
opened 2026-01-22 15:33:34 +01:00 by admin · 2 comments
Owner

Originally created by @lsrzj on GitHub (Apr 30, 2020).

I have a inheritance of three levels using class table inheritance like this:

Class Test


    namespace App\Entities\Test;
    
    use Doctrine\ORM\Mapping as ORM;
    
    /**
     * Class Test
     * @package App\Entities\Test
     * @ORM\Entity
     * @ORM\InheritanceType("JOINED")
     * @ORM\DiscriminatorColumn(name="discr", type="string")
     * @ORM\DiscriminatorMap({"TestA" = "TestA", "TestB" = "TestB"})
     * @ORM\Table(name="test")
     */
    abstract class Test {
    
      /**
       * @var integer
       * @ORM\Column(type="integer")
       * @ORM\Id
       * @ORM\GeneratedValue(strategy="IDENTITY")
       */
      protected $id;
    
      /**
       * @var string
       * @ORM\Column(type="string")
       */
      protected $columnTest;
    }

Class TestM extends Test

   
    namespace App\Entities\Test;
    
    use Doctrine\ORM\Mapping as ORM;
    
    /**
     * Class TestM
     * @package App\Entities\Test
     * @ORM\Entity
     */
    abstract class TestM extends Test{
    
      /**
       * @var string
       * @ORM\Column(type="string")
       */
      protected $columnTestM;
    
    }

Class TestA extends TestM

   
    namespace App\Entities\Test;
    
    use Doctrine\ORM\Mapping as ORM;
    
    /**
     * Class TestA
     * @package App\Entities\Test
     * @ORM\Entity
     */
    class TestA extends TestM{
    
      /**
       * @var string
       * @ORM\Column(type="string")
       */
      private $columnTestA;
    
      public function __construct(string $columnTest, string $columnTestM, string $columnTestA) {
        $this->columnTest = $columnTest;
        $this->columnTestM = $columnTestM;
        $this->columnTestA = $columnTestA;
      }
    
      /**
       * @return string
       */
      public function getColumnTest(): string {
        return $this->columnTest;
      }
    
      /**
       * @param string $columnTest
       */
      public function setColumnTest(string $columnTest): void {
        $this->columnTest = $columnTest;
      }
    
      /**
       * @return string
       */
      public function getColumnTestM(): string {
        return $this->columnTestM;
      }
    
      /**
       * @param string $columnTestM
       */
      public function setColumnTestM(string $columnTestM): void {
        $this->columnTestM = $columnTestM;
      }
    
      /**
       * @return string
       */
      public function getColumnTestA(): string {
        return $this->columnTestA;
      }
    
      /**
       * @param string $columnTestA
       */
      public function setColumnTestA(string $columnTestA): void {
        $this->columnTestA = $columnTestA;
      }
    }

I'm having problem because, when I'm going to retrieve the entity from my DB, it comes with the second level with no data, only the first and last levels comes with all the data. Notice that columnTestM is blank. Is it a bug or am I missing something? It's persisting all three levels with data, the problem is only when I have to get it. As an example I put the column's content with it's own name

>>> print_r(\EntityManager::getRepository('App\Entities\Test\Test')->find(1));
App\Entities\Test\TestA Object
(
    [columnTestA:App\Entities\Test\TestA:private] => columnTestA
    [columnTestM:protected] => 
    [id:protected] => 1
    [columnTest:protected] => columnTest
)

EDIT:

I put my MariaDB to log all queries to check what query was being generated and I noticed that, instead of generating a query that involves TestM, it tries to left join with TestB. Below the generated query:

SELECT 
    t0.id AS id_3,
    t0.column_test AS column_test_4,
    t0.discr,
    t1.column_test_a AS column_test_a_5,
    t2.column_test_b AS column_test_b_6
FROM
    test t0
        LEFT JOIN
    test_as t1 ON t0.id = t1.id
        LEFT JOIN
    test_bs t2 ON t0.id = t2.id
WHERE
    t0.id = 1
Originally created by @lsrzj on GitHub (Apr 30, 2020). I have a inheritance of three levels using class table inheritance like this: Class Test ```php namespace App\Entities\Test; use Doctrine\ORM\Mapping as ORM; /** * Class Test * @package App\Entities\Test * @ORM\Entity * @ORM\InheritanceType("JOINED") * @ORM\DiscriminatorColumn(name="discr", type="string") * @ORM\DiscriminatorMap({"TestA" = "TestA", "TestB" = "TestB"}) * @ORM\Table(name="test") */ abstract class Test { /** * @var integer * @ORM\Column(type="integer") * @ORM\Id * @ORM\GeneratedValue(strategy="IDENTITY") */ protected $id; /** * @var string * @ORM\Column(type="string") */ protected $columnTest; } ``` Class TestM extends Test ```php namespace App\Entities\Test; use Doctrine\ORM\Mapping as ORM; /** * Class TestM * @package App\Entities\Test * @ORM\Entity */ abstract class TestM extends Test{ /** * @var string * @ORM\Column(type="string") */ protected $columnTestM; } ``` Class TestA extends TestM ```php namespace App\Entities\Test; use Doctrine\ORM\Mapping as ORM; /** * Class TestA * @package App\Entities\Test * @ORM\Entity */ class TestA extends TestM{ /** * @var string * @ORM\Column(type="string") */ private $columnTestA; public function __construct(string $columnTest, string $columnTestM, string $columnTestA) { $this->columnTest = $columnTest; $this->columnTestM = $columnTestM; $this->columnTestA = $columnTestA; } /** * @return string */ public function getColumnTest(): string { return $this->columnTest; } /** * @param string $columnTest */ public function setColumnTest(string $columnTest): void { $this->columnTest = $columnTest; } /** * @return string */ public function getColumnTestM(): string { return $this->columnTestM; } /** * @param string $columnTestM */ public function setColumnTestM(string $columnTestM): void { $this->columnTestM = $columnTestM; } /** * @return string */ public function getColumnTestA(): string { return $this->columnTestA; } /** * @param string $columnTestA */ public function setColumnTestA(string $columnTestA): void { $this->columnTestA = $columnTestA; } } ``` I'm having problem because, when I'm going to retrieve the entity from my DB, it comes with the second level with no data, only the first and last levels comes with all the data. Notice that columnTestM is blank. Is it a bug or am I missing something? It's persisting all three levels with data, the problem is only when I have to get it. As an example I put the column's content with it's own name >>> print_r(\EntityManager::getRepository('App\Entities\Test\Test')->find(1)); App\Entities\Test\TestA Object ( [columnTestA:App\Entities\Test\TestA:private] => columnTestA [columnTestM:protected] => [id:protected] => 1 [columnTest:protected] => columnTest ) **EDIT:** I put my MariaDB to log all queries to check what query was being generated and I noticed that, instead of generating a query that involves TestM, it tries to left join with TestB. Below the generated query: ```sql SELECT t0.id AS id_3, t0.column_test AS column_test_4, t0.discr, t1.column_test_a AS column_test_a_5, t2.column_test_b AS column_test_b_6 FROM test t0 LEFT JOIN test_as t1 ON t0.id = t1.id LEFT JOIN test_bs t2 ON t0.id = t2.id WHERE t0.id = 1 ```
admin closed this issue 2026-01-22 15:33:35 +01:00
Author
Owner

@mpdude commented on GitHub (Jan 13, 2023):

Your discriminator map does not contain the abstract entity from the middle of the hierarchy.

Follow #10389 to find out if that is a misconfiguration on your side and the issue being invalid; or it is a valid issue and #10388 at least showing test cases (not fix yet).

@mpdude commented on GitHub (Jan 13, 2023): Your discriminator map does not contain the abstract entity from the middle of the hierarchy. Follow #10389 to find out if that is a misconfiguration on your side and the issue being invalid; or it is a valid issue and #10388 at least showing test cases (not fix yet).
Author
Owner

@mpdude commented on GitHub (Jan 18, 2023):

#10411 takes care of filling the missing abstract classes in the DM, and your example should now be working.

@mpdude commented on GitHub (Jan 18, 2023): #10411 takes care of filling the missing abstract classes in the DM, and your example should now be working.
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: doctrine/archived-orm#6458