mirror of
https://github.com/doctrine/orm.git
synced 2026-03-23 22:42:18 +01:00
Add new SqlWalker Hint to manually specify inherited sub-classes to outer join #6488
Reference in New Issue
Block a user
Delete Branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
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 calledNodesSources. 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 genericNodesSourcesqueries. 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 OFDQL 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\SqlWalkeris not overrideable at all. There are too muchprivatemethods and code logic is not decoupled enough to write a customTreeWalkerimplementation without duplicating 99% ofSqlWalkercode base. And if I need to override onlySqlWalker, allDoctrine\ORM\Query\Exec\…classes require aSqlWalkerinstance and not aTreeWalkerinstance… so I’m stuck if I don’t want to fork the entireDoctrine\ORM\Querynamespace in my project.Summary
This is just a quick-and-dirty implementation in
SqlWalker: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
SqlWalkerwhile securing its constructor. That way, we don’t have to introduce to much custom code into Doctrine core :@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.
@ambroisemaupate commented on GitHub (Jun 10, 2020):
Thank you for your answer @beberlei
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
SqlWalkerextension 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.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.7andmasterbranch.@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.