Add new SqlWalker Hint to manually specify inherited sub-classes to outer join #6488

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

Originally created by @ambroisemaupate on GitHub (Jun 9, 2020).

Feature Request

In Roadiz CMS we use a polymorphic content base. All contents tables are sub-classes of a @ORM\InheritanceType("JOINED") entity called NodesSources. If a website is built with more than 10 content-types there will be more than 10 subclasses that will be outer-joined for each generic NodesSources queries. Because I don’t want to select strict content-types in the context of building a website page containing many content blocks, etc… I cannot directly use the leaf entity repository to generate optimized DQL queries.

So I want to optimized my queries by only selecting content types using INSTANCE OF DQL operator to generate the following query criteria: n0_.discr IN ('page','homepage','blogpost', 'contentblock', 'contactblock').

Then, if I "secured" my DQL query by selected only the right sub-classes I need, I should be able to only join and select class fields from these only sub-classes too.

For the moment Doctrine\ORM\Query\SqlWalker is not overrideable at all. There are too much private methods and code logic is not decoupled enough to write a custom TreeWalker implementation without duplicating 99% of SqlWalker code base. And if I need to override only SqlWalker, all Doctrine\ORM\Query\Exec\… classes require a SqlWalker instance and not a TreeWalker instance… so I’m stuck if I don’t want to fork the entire Doctrine\ORM\Query namespace in my project.

Q A
New Feature yes
RFC no
BC Break no

Summary

This is just a quick-and-dirty implementation in SqlWalker:

diff --git a/lib/Doctrine/ORM/Query.php b/lib/Doctrine/ORM/Query.php
index 47a5812e3..26a881c8a 100644
--- a/lib/Doctrine/ORM/Query.php
+++ b/lib/Doctrine/ORM/Query.php
@@ -99,6 +99,13 @@ final class Query extends AbstractQuery
 
     public const HINT_LOCK_MODE = 'doctrine.lockMode';
 
+    /**
+     * An array of class names to filter Class Table Inheritance sub-classes.
+     * Use this hint at your own risks. You must use this hint along with INSTANCE OF query filter
+     * to ensure data consistency.
+     */
+    public const HINT_CUSTOM_SUBCLASS_NAMES = 'doctrine.customSubClassNames';
+
     /**
      * The current state of this query.
      *
diff --git a/lib/Doctrine/ORM/Query/SqlWalker.php b/lib/Doctrine/ORM/Query/SqlWalker.php
index 7fab4b5c2..9cec3c586 100644
--- a/lib/Doctrine/ORM/Query/SqlWalker.php
+++ b/lib/Doctrine/ORM/Query/SqlWalker.php
@@ -356,8 +356,17 @@ class SqlWalker implements TreeWalker
             return $sql;
         }
 
+        $subClassesNames = $class->getSubClasses();
+        if ($this->query->hasHint(Query::HINT_CUSTOM_SUBCLASS_NAMES) &&
+            count($this->query->getHint(Query::HINT_CUSTOM_SUBCLASS_NAMES))) {
+            $subClassesNames = array_intersect(
+                $subClassesNames,
+                $this->query->getHint(Query::HINT_CUSTOM_SUBCLASS_NAMES)
+            );
+        }
+
         // LEFT JOIN child class tables
-        foreach ($class->getSubClasses() as $subClassName) {
+        foreach ($subClassesNames as $subClassName) {
             $subClass   = $this->em->getClassMetadata($subClassName);
             $tableName  = $subClass->table->getQuotedQualifiedName($this->platform);
             $tableAlias = $this->getSQLTableAlias($subClass->getTableName(), $dqlAlias);
@@ -1454,7 +1463,15 @@ class SqlWalker implements TreeWalker
                 // 2) on Class Table Inheritance only if partial objects are disallowed,
                 //    since it requires outer joining subtables.
                 if ($class->inheritanceType === InheritanceType::SINGLE_TABLE || ! $this->query->getHint(Query::HINT_FORCE_PARTIAL_LOAD)) {
-                    foreach ($class->getSubClasses() as $subClassName) {
+                    $subClassesNames = $class->getSubClasses();
+                    if ($this->query->hasHint(Query::HINT_CUSTOM_SUBCLASS_NAMES) &&
+                        count($this->query->getHint(Query::HINT_CUSTOM_SUBCLASS_NAMES))) {
+                        $subClassesNames = array_intersect(
+                            $subClassesNames,
+                            $this->query->getHint(Query::HINT_CUSTOM_SUBCLASS_NAMES)
+                        );
+                    }
+                    foreach ($subClassesNames as $subClassName) {
                         $subClass = $this->em->getClassMetadata($subClassName);
 
                         foreach ($subClass->getPropertiesIterator() as $fieldName => $property) {

You’ll find the same issue on Roadiz CMS side:
https://github.com/roadiz/roadiz/issues/366


The other solution would be to allow third party developers to extend SqlWalker while securing its constructor. That way, we don’t have to introduce to much custom code into Doctrine core :

diff --git a/lib/Doctrine/ORM/Query/SqlWalker.php b/lib/Doctrine/ORM/Query/SqlWalker.php
index 7fab4b5c2..ad3d0aaa3 100644
--- a/lib/Doctrine/ORM/Query/SqlWalker.php
+++ b/lib/Doctrine/ORM/Query/SqlWalker.php
@@ -49,99 +49,99 @@ class SqlWalker implements TreeWalker
     public const HINT_DISTINCT = 'doctrine.distinct';
 
     /** @var ResultSetMapping */
-    private $rsm;
+    protected $rsm;
 
     /**
      * Counter for generating unique column aliases.
      *
      * @var int
      */
-    private $aliasCounter = 0;
+    protected $aliasCounter = 0;
 
     /**
      * Counter for generating unique table aliases.
      *
      * @var int
      */
-    private $tableAliasCounter = 0;
+    protected $tableAliasCounter = 0;
 
     /**
      * Counter for generating unique scalar result.
      *
      * @var int
      */
-    private $scalarResultCounter = 1;
+    protected $scalarResultCounter = 1;
 
     /**
      * Counter for generating unique parameter indexes.
      *
      * @var int
      */
-    private $sqlParamIndex = 0;
+    protected $sqlParamIndex = 0;
 
     /**
      * Counter for generating indexes.
      *
      * @var int
      */
-    private $newObjectCounter = 0;
+    protected $newObjectCounter = 0;
 
     /** @var ParserResult */
-    private $parserResult;
+    protected $parserResult;
 
     /** @var EntityManagerInterface */
-    private $em;
+    protected $em;
 
     /** @var Connection */
-    private $conn;
+    protected $conn;
 
     /** @var AbstractQuery */
-    private $query;
+    protected $query;
 
     /** @var string[] */
-    private $tableAliasMap = [];
+    protected $tableAliasMap = [];
 
     /**
      * Map from result variable names to their SQL column alias names.
      *
      * @var string[]|string[][]
      */
-    private $scalarResultAliasMap = [];
+    protected $scalarResultAliasMap = [];
 
     /**
      * Map from Table-Alias + Column-Name to OrderBy-Direction.
      *
      * @var mixed[]
      */
-    private $orderedColumnsMap = [];
+    protected $orderedColumnsMap = [];
 
     /**
      * Map from DQL-Alias + Field-Name to SQL Column Alias.
      *
      * @var string[][]
      */
-    private $scalarFields = [];
+    protected $scalarFields = [];
 
     /**
      * Map of all components/classes that appear in the DQL query.
      *
      * @var mixed[][]
      */
-    private $queryComponents;
+    protected $queryComponents;
 
     /**
      * A list of classes that appear in non-scalar SelectExpressions.
      *
      * @var mixed[][]
      */
-    private $selectedClasses = [];
+    protected $selectedClasses = [];
 
     /**
      * The DQL alias of the root class of the currently traversed query.
      *
      * @var string[]
      */
-    private $rootAliases = [];
+    protected $rootAliases = [];
 
     /**
      * Flag that indicates whether to generate SQL table aliases in the SQL.
@@ -149,19 +149,19 @@ class SqlWalker implements TreeWalker
      *
      * @var bool
      */
-    private $useSqlTableAliases = true;
+    protected $useSqlTableAliases = true;
 
     /**
      * The database platform abstraction.
      *
      * @var AbstractPlatform
      */
-    private $platform;
+    protected $platform;
 
     /**
      * {@inheritDoc}
      */
-    public function __construct(AbstractQuery $query, ParserResult $parserResult, array $queryComponents)
+    public final function __construct(AbstractQuery $query, ParserResult $parserResult, array $queryComponents)
     {
         $this->query           = $query;
         $this->parserResult    = $parserResult;
@@ -316,7 +316,7 @@ class SqlWalker implements TreeWalker
      *
      * @return string The SQL.
      */
-    private function generateClassTableInheritanceJoins($class, $dqlAlias)
+    protected function generateClassTableInheritanceJoins($class, $dqlAlias)
     {
         $sql = '';
 
@@ -381,7 +381,7 @@ class SqlWalker implements TreeWalker
     /**
      * @return string
      */
-    private function generateOrderedCollectionOrderByItems()
+    protected function generateOrderedCollectionOrderByItems()
     {
         $orderedColumns = [];
 
@@ -420,7 +420,7 @@ class SqlWalker implements TreeWalker
      *
      * @return string
      */
-    private function generateDiscriminatorColumnConditionSQL(array $dqlAliases)
+    protected function generateDiscriminatorColumnConditionSQL(array $dqlAliases)
     {
         $sqlParts = [];
 
@@ -469,7 +469,7 @@ class SqlWalker implements TreeWalker
      *
      * @return string The SQL query part to add to a query.
      */
-    private function generateFilterConditionSQL(ClassMetadata $targetEntity, $targetTableAlias)
+    protected function generateFilterConditionSQL(ClassMetadata $targetEntity, $targetTableAlias)
     {
         if (! $this->em->hasFilters()) {
             return '';
@@ -903,7 +903,7 @@ class SqlWalker implements TreeWalker
      *
      * @param AST\RangeVariableDeclaration $rangeVariableDeclaration
      */
-    private function generateRangeVariableDeclarationSQL($rangeVariableDeclaration, bool $buildNestedJoins) : string
+    protected function generateRangeVariableDeclarationSQL($rangeVariableDeclaration, bool $buildNestedJoins) : string
     {
         $class    = $this->em->getClassMetadata($rangeVariableDeclaration->abstractSchemaName);
         $dqlAlias = $rangeVariableDeclaration->aliasIdentificationVariable;
@@ -2366,7 +2366,7 @@ class SqlWalker implements TreeWalker
      *
      * @throws QueryException
      */
-    private function getChildDiscriminatorsFromClassMetadata(ClassMetadata $rootClass, AST\InstanceOfExpression $instanceOfExpr) : string
+    protected function getChildDiscriminatorsFromClassMetadata(ClassMetadata $rootClass, AST\InstanceOfExpression $instanceOfExpr) : string
     {
         $sqlParameterList = [];
         $discriminators   = [];
Originally created by @ambroisemaupate on GitHub (Jun 9, 2020). ### Feature Request In *Roadiz CMS* we use a polymorphic content base. All contents tables are sub-classes of a `@ORM\InheritanceType("JOINED")` entity called `NodesSources`. If a website is built with more than 10 content-types there will be more than 10 subclasses that will be outer-joined for each generic `NodesSources` queries. Because I don’t want to select strict content-types in the context of building a website page containing many content blocks, etc… I cannot directly use the *leaf* entity repository to generate optimized DQL queries. So I want to optimized my queries by only selecting content types using `INSTANCE OF` DQL operator to generate the following query criteria: `n0_.discr IN ('page','homepage','blogpost', 'contentblock', 'contactblock')`. Then, if I *"secured"* my DQL query by selected only the right sub-classes I need, I should be able to **only** join and select class fields from these only sub-classes too. For the moment `Doctrine\ORM\Query\SqlWalker` is not overrideable at all. There are too much `private` methods and code logic is not decoupled enough to write a custom `TreeWalker` implementation without duplicating 99% of `SqlWalker` code base. And if I need to override only `SqlWalker`, all `Doctrine\ORM\Query\Exec\…` classes require a `SqlWalker` instance and not a `TreeWalker` instance… so I’m stuck if I don’t want to fork the entire `Doctrine\ORM\Query` namespace in my project. | Q | A |------------ | ------ | New Feature | yes | RFC | no | BC Break | no #### Summary This is just a quick-and-dirty implementation in `SqlWalker`: ```diff diff --git a/lib/Doctrine/ORM/Query.php b/lib/Doctrine/ORM/Query.php index 47a5812e3..26a881c8a 100644 --- a/lib/Doctrine/ORM/Query.php +++ b/lib/Doctrine/ORM/Query.php @@ -99,6 +99,13 @@ final class Query extends AbstractQuery public const HINT_LOCK_MODE = 'doctrine.lockMode'; + /** + * An array of class names to filter Class Table Inheritance sub-classes. + * Use this hint at your own risks. You must use this hint along with INSTANCE OF query filter + * to ensure data consistency. + */ + public const HINT_CUSTOM_SUBCLASS_NAMES = 'doctrine.customSubClassNames'; + /** * The current state of this query. * diff --git a/lib/Doctrine/ORM/Query/SqlWalker.php b/lib/Doctrine/ORM/Query/SqlWalker.php index 7fab4b5c2..9cec3c586 100644 --- a/lib/Doctrine/ORM/Query/SqlWalker.php +++ b/lib/Doctrine/ORM/Query/SqlWalker.php @@ -356,8 +356,17 @@ class SqlWalker implements TreeWalker return $sql; } + $subClassesNames = $class->getSubClasses(); + if ($this->query->hasHint(Query::HINT_CUSTOM_SUBCLASS_NAMES) && + count($this->query->getHint(Query::HINT_CUSTOM_SUBCLASS_NAMES))) { + $subClassesNames = array_intersect( + $subClassesNames, + $this->query->getHint(Query::HINT_CUSTOM_SUBCLASS_NAMES) + ); + } + // LEFT JOIN child class tables - foreach ($class->getSubClasses() as $subClassName) { + foreach ($subClassesNames as $subClassName) { $subClass = $this->em->getClassMetadata($subClassName); $tableName = $subClass->table->getQuotedQualifiedName($this->platform); $tableAlias = $this->getSQLTableAlias($subClass->getTableName(), $dqlAlias); @@ -1454,7 +1463,15 @@ class SqlWalker implements TreeWalker // 2) on Class Table Inheritance only if partial objects are disallowed, // since it requires outer joining subtables. if ($class->inheritanceType === InheritanceType::SINGLE_TABLE || ! $this->query->getHint(Query::HINT_FORCE_PARTIAL_LOAD)) { - foreach ($class->getSubClasses() as $subClassName) { + $subClassesNames = $class->getSubClasses(); + if ($this->query->hasHint(Query::HINT_CUSTOM_SUBCLASS_NAMES) && + count($this->query->getHint(Query::HINT_CUSTOM_SUBCLASS_NAMES))) { + $subClassesNames = array_intersect( + $subClassesNames, + $this->query->getHint(Query::HINT_CUSTOM_SUBCLASS_NAMES) + ); + } + foreach ($subClassesNames as $subClassName) { $subClass = $this->em->getClassMetadata($subClassName); foreach ($subClass->getPropertiesIterator() as $fieldName => $property) { ``` You’ll find the same issue on *Roadiz* CMS side: https://github.com/roadiz/roadiz/issues/366 --- The other solution would be to allow third party developers to extend `SqlWalker` while securing its *constructor*. That way, we don’t have to introduce to much custom code into Doctrine core : ```diff diff --git a/lib/Doctrine/ORM/Query/SqlWalker.php b/lib/Doctrine/ORM/Query/SqlWalker.php index 7fab4b5c2..ad3d0aaa3 100644 --- a/lib/Doctrine/ORM/Query/SqlWalker.php +++ b/lib/Doctrine/ORM/Query/SqlWalker.php @@ -49,99 +49,99 @@ class SqlWalker implements TreeWalker public const HINT_DISTINCT = 'doctrine.distinct'; /** @var ResultSetMapping */ - private $rsm; + protected $rsm; /** * Counter for generating unique column aliases. * * @var int */ - private $aliasCounter = 0; + protected $aliasCounter = 0; /** * Counter for generating unique table aliases. * * @var int */ - private $tableAliasCounter = 0; + protected $tableAliasCounter = 0; /** * Counter for generating unique scalar result. * * @var int */ - private $scalarResultCounter = 1; + protected $scalarResultCounter = 1; /** * Counter for generating unique parameter indexes. * * @var int */ - private $sqlParamIndex = 0; + protected $sqlParamIndex = 0; /** * Counter for generating indexes. * * @var int */ - private $newObjectCounter = 0; + protected $newObjectCounter = 0; /** @var ParserResult */ - private $parserResult; + protected $parserResult; /** @var EntityManagerInterface */ - private $em; + protected $em; /** @var Connection */ - private $conn; + protected $conn; /** @var AbstractQuery */ - private $query; + protected $query; /** @var string[] */ - private $tableAliasMap = []; + protected $tableAliasMap = []; /** * Map from result variable names to their SQL column alias names. * * @var string[]|string[][] */ - private $scalarResultAliasMap = []; + protected $scalarResultAliasMap = []; /** * Map from Table-Alias + Column-Name to OrderBy-Direction. * * @var mixed[] */ - private $orderedColumnsMap = []; + protected $orderedColumnsMap = []; /** * Map from DQL-Alias + Field-Name to SQL Column Alias. * * @var string[][] */ - private $scalarFields = []; + protected $scalarFields = []; /** * Map of all components/classes that appear in the DQL query. * * @var mixed[][] */ - private $queryComponents; + protected $queryComponents; /** * A list of classes that appear in non-scalar SelectExpressions. * * @var mixed[][] */ - private $selectedClasses = []; + protected $selectedClasses = []; /** * The DQL alias of the root class of the currently traversed query. * * @var string[] */ - private $rootAliases = []; + protected $rootAliases = []; /** * Flag that indicates whether to generate SQL table aliases in the SQL. @@ -149,19 +149,19 @@ class SqlWalker implements TreeWalker * * @var bool */ - private $useSqlTableAliases = true; + protected $useSqlTableAliases = true; /** * The database platform abstraction. * * @var AbstractPlatform */ - private $platform; + protected $platform; /** * {@inheritDoc} */ - public function __construct(AbstractQuery $query, ParserResult $parserResult, array $queryComponents) + public final function __construct(AbstractQuery $query, ParserResult $parserResult, array $queryComponents) { $this->query = $query; $this->parserResult = $parserResult; @@ -316,7 +316,7 @@ class SqlWalker implements TreeWalker * * @return string The SQL. */ - private function generateClassTableInheritanceJoins($class, $dqlAlias) + protected function generateClassTableInheritanceJoins($class, $dqlAlias) { $sql = ''; @@ -381,7 +381,7 @@ class SqlWalker implements TreeWalker /** * @return string */ - private function generateOrderedCollectionOrderByItems() + protected function generateOrderedCollectionOrderByItems() { $orderedColumns = []; @@ -420,7 +420,7 @@ class SqlWalker implements TreeWalker * * @return string */ - private function generateDiscriminatorColumnConditionSQL(array $dqlAliases) + protected function generateDiscriminatorColumnConditionSQL(array $dqlAliases) { $sqlParts = []; @@ -469,7 +469,7 @@ class SqlWalker implements TreeWalker * * @return string The SQL query part to add to a query. */ - private function generateFilterConditionSQL(ClassMetadata $targetEntity, $targetTableAlias) + protected function generateFilterConditionSQL(ClassMetadata $targetEntity, $targetTableAlias) { if (! $this->em->hasFilters()) { return ''; @@ -903,7 +903,7 @@ class SqlWalker implements TreeWalker * * @param AST\RangeVariableDeclaration $rangeVariableDeclaration */ - private function generateRangeVariableDeclarationSQL($rangeVariableDeclaration, bool $buildNestedJoins) : string + protected function generateRangeVariableDeclarationSQL($rangeVariableDeclaration, bool $buildNestedJoins) : string { $class = $this->em->getClassMetadata($rangeVariableDeclaration->abstractSchemaName); $dqlAlias = $rangeVariableDeclaration->aliasIdentificationVariable; @@ -2366,7 +2366,7 @@ class SqlWalker implements TreeWalker * * @throws QueryException */ - private function getChildDiscriminatorsFromClassMetadata(ClassMetadata $rootClass, AST\InstanceOfExpression $instanceOfExpr) : string + protected function getChildDiscriminatorsFromClassMetadata(ClassMetadata $rootClass, AST\InstanceOfExpression $instanceOfExpr) : string { $sqlParameterList = []; $discriminators = []; ```
admin closed this issue 2026-01-22 15:33:58 +01:00
Author
Owner

@beberlei commented on GitHub (Jun 9, 2020):

I feel you are misusing inheritence here. There will be other limits where this approach, where Doctrine cannot help anymore, like the upper limit of possible joins per query that each database has and which is quite low (63 for MySQL I believe).

The number of entities in a joined inheritance hierachy should be a fixed, and known number, maybe 5-10.

Your request does make sense to some extend, when instanceof is used than you can actually limit the joins by using this information. But it doesn't change the fact that you will sometimes need the whole hierachy (I assume) and this is going to lead these query monsters.

With the CMS use-case, it is a hard problem to map a document to a relational database (and why the concept of Document database exists), but I would recommend looking at some form of aggregation, or dynamic properties (like a json field in the node) instead.

@beberlei commented on GitHub (Jun 9, 2020): I feel you are misusing inheritence here. There will be other limits where this approach, where Doctrine cannot help anymore, like the upper limit of possible joins per query that each database has and which is quite low (63 for MySQL I believe). The number of entities in a joined inheritance hierachy should be a fixed, and known number, maybe 5-10. Your request does make sense to some extend, when instanceof is used than you can actually limit the joins by using this information. But it doesn't change the fact that you will sometimes need the whole hierachy (I assume) and this is going to lead these query monsters. With the CMS use-case, it is a hard problem to map a document to a relational database (and why the concept of Document database exists), but I would recommend looking at some form of aggregation, or dynamic properties (like a json field in the node) instead.
Author
Owner

@ambroisemaupate commented on GitHub (Jun 10, 2020):

Thank you for your answer @beberlei

But it doesn't change the fact that you will sometimes need the whole hierachy (I assume) and this is going to lead these query monsters.

In fact this is a current optimization issue on our side. We try to specify as often as possible every sub-classes to filter out useless fields and joins. Cases where loading the whole hierarchy would be very specific. That’s why SqlWalker extension seems to me a good "first" solution. Then if we have websites with more than 40 node types, the Document database should be a better solution, I agree. For the moment these cases are very rare. Small to medium sized websites using Roadiz CMS count 10-15 node-types and usually there are only 1-3 fields in the sub-class because others relations (such as Media objects, related content, nested tree) are joined at the super-class level.

it is a hard problem to map a document to a relational database (and why the concept of Document database exists)

Yes I digged a little into it, but mixing RDBS and a Document DB in the same website is harder and often overkill for small to medium websites. A polymorphic DB based CMS is so convenient to develop websites quickly that we prefer spending time on optimizing that one system rather than going custom for each case.

I can find time to submit a pull request on each solution above, for 2.7 and master branch.

@ambroisemaupate commented on GitHub (Jun 10, 2020): Thank you for your answer @beberlei > But it doesn't change the fact that you will sometimes need the whole hierachy (I assume) and this is going to lead these query monsters. In fact this is a current optimization issue on our side. We try to specify as often as possible every sub-classes to filter out useless fields and joins. Cases where loading the whole hierarchy would be very specific. That’s why `SqlWalker` extension seems to me a good "first" solution. Then if we have websites with more than 40 node types, the Document database should be a better solution, I agree. For the moment these cases are very rare. Small to medium sized websites using Roadiz CMS count 10-15 node-types and usually there are only 1-3 fields in the sub-class because others relations (such as Media objects, related content, nested tree) are joined at the super-class level. > it is a hard problem to map a document to a relational database (and why the concept of Document database exists) Yes I digged a little into it, but mixing RDBS and a Document DB in the same website is harder and often overkill for small to medium websites. A polymorphic DB based CMS is so convenient to develop websites quickly that we prefer spending time on optimizing that one system rather than going custom for each case. I can find time to submit a pull request on each solution above, for `2.7` and `master` branch.
Author
Owner

@beberlei commented on GitHub (Jun 10, 2020):

As I mentioned we think this is not a right use of class table inheritence, you are much better off with just one NodeSource entity and a JSON column with a payload for each specific node. With more recent versions of MySQL and PostgreSQL its even possible to index these.

Another strategy could be using single table inheritance, and use a json payload on the parent class and have the children only implement methods that abstract working with the payload, but not actually add their own columns.

I am going to be honest, that it is very unlikely that we are making changes into this direction and I am closing this issue.

@beberlei commented on GitHub (Jun 10, 2020): As I mentioned we think this is not a right use of class table inheritence, you are much better off with just one NodeSource entity and a JSON column with a payload for each specific node. With more recent versions of MySQL and PostgreSQL its even possible to index these. Another strategy could be using single table inheritance, and use a json payload on the parent class and have the children only implement methods that abstract working with the payload, but not actually add their own columns. I am going to be honest, that it is very unlikely that we are making changes into this direction and I am closing this issue.
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: doctrine/archived-orm#6488