DDC-1681: loadRelated() - Method to efficiently load sets of related entities in "sub"-select strategies #2113

Open
opened 2026-01-22 13:41:25 +01:00 by admin · 6 comments
Owner

Originally created by @doctrinebot on GitHub (Mar 5, 2012).

Originally assigned to: @guilhermeblanco on GitHub.

Jira issue originally created by user @beberlei:

As per Request of Seldaek ;)

Originally created by @doctrinebot on GitHub (Mar 5, 2012). Originally assigned to: @guilhermeblanco on GitHub. Jira issue originally created by user @beberlei: As per Request of Seldaek ;)
admin added the New Feature label 2026-01-22 13:41:25 +01:00
Author
Owner

@doctrinebot commented on GitHub (Mar 5, 2012):

Comment created by seldaek:

Sample:

$result = $queryBuilder->select('a')->from('User', 'a')->getQuery()->getResult();
$result->loadRelated('roles'); // loads all a.roles

Would be the equivalent of:

$result = $queryBuilder->select('a, r')->from('User', 'a')->join('a.roles', 'r')->getQuery()->getResult();

Except that the above does one simple query without join, then one WHERE IN query with all ids from the collection.
The latter obviously does a join and retrieves everything in one - more complex - query.

Bonus points if you can loadRelated multiple relations at once.

@doctrinebot commented on GitHub (Mar 5, 2012): Comment created by seldaek: Sample: ``` $result = $queryBuilder->select('a')->from('User', 'a')->getQuery()->getResult(); $result->loadRelated('roles'); // loads all a.roles ``` Would be the equivalent of: ``` $result = $queryBuilder->select('a, r')->from('User', 'a')->join('a.roles', 'r')->getQuery()->getResult(); ``` Except that the above does one simple query without join, then one WHERE IN query with all ids from the collection. The latter obviously does a join and retrieves everything in one - more complex - query. Bonus points if you can loadRelated multiple relations at once.
Author
Owner

@doctrinebot commented on GitHub (Mar 5, 2012):

Comment created by stof:

I see an issue here: if you do a WHERE IN with the multiple ids, how do you know which entity the role is related to ?

and btw, the interface you suggested above would require breaking the BC: $result is an array right now.

@doctrinebot commented on GitHub (Mar 5, 2012): Comment created by stof: I see an issue here: if you do a WHERE IN with the multiple ids, how do you know which entity the role is related to ? and btw, the interface you suggested above would require breaking the BC: `$result` is an array right now.
Author
Owner

@doctrinebot commented on GitHub (Mar 5, 2012):

Comment created by seldaek:

The interface is just an example mimicking the way it worked in D1, take it with a grain of salt.

As for the implementation, if you assume the roles table has a user_id and role column, then you can do WHERE user_id IN (1, 2, 3) and you'll get back the user ids so you know where to attach them. It might still require some joining in some cases, but the point is to keep the joins out of the main query.

@doctrinebot commented on GitHub (Mar 5, 2012): Comment created by seldaek: The interface is just an example mimicking the way it worked in D1, take it with a grain of salt. As for the implementation, if you assume the roles table has a user_id and role column, then you can do WHERE user_id IN (1, 2, 3) and you'll get back the user ids so you know where to attach them. It might still require some joining in some cases, but the point is to keep the joins out of the main query.
Author
Owner

@doctrinebot commented on GitHub (Mar 5, 2012):

Comment created by @guilhermeblanco:

The one to be implemented would be:

$result = $queryBuilder->select('a')->from('User', 'a')->getQuery()->getResult();
$em->loadRelated($result, 'roles'); // loads all a.roles

The reason for that is not all the times you have a PersistentCollection. You may have an ArrayCollection too.
I just don't know yet how to handle array and ArrayCollection situations, since you may not know which class you're trying to fetch.
Maybe I can try to grab the first item of array and retrieve Association information from ClassMetadata retrieved via get_class on first item. That would solve the problem.

Any other ideas, feel free to give me.

@doctrinebot commented on GitHub (Mar 5, 2012): Comment created by @guilhermeblanco: The one to be implemented would be: ``` $result = $queryBuilder->select('a')->from('User', 'a')->getQuery()->getResult(); $em->loadRelated($result, 'roles'); // loads all a.roles ``` The reason for that is not all the times you have a PersistentCollection. You may have an ArrayCollection too. I just don't know yet how to handle array and ArrayCollection situations, since you may not know which class you're trying to fetch. Maybe I can try to grab the first item of array and retrieve Association information from ClassMetadata retrieved via get_class on first item. That would solve the problem. Any other ideas, feel free to give me.
Author
Owner

@doctrinebot commented on GitHub (Sep 6, 2013):

Comment created by sirian:

Any news? it's really cool to use "WHERE primary_key IN " instead of joins.

@doctrinebot commented on GitHub (Sep 6, 2013): Comment created by sirian: Any news? it's really cool to use "WHERE primary_key IN " instead of joins.
Author
Owner

@outtersg commented on GitHub (Sep 10, 2023):

Having exactly the same need, I was wondering if any official solution emerged and could allow closing the issue.

Else I would be glad to participate, having a real use for it (junior developers that add 5-level "foreach"es, and senior developers being too few to recraft it and teach; so senior ones end up wanting to put some "easy" loadRelated()s, to avoid multi-minutes recursive fetching in production, and let themselves time to make junior ones become more careful, and then become more senior).

@guilhermeblanco, regarding "The one to be implemented would be: $em->loadRelated()",
wouldn't we want the two to be implemented would be: $em->loadRelated() and PersistentCollection->loadRelated()?
This would allow syntactic sugar (avoid repeating $em), and chaining:

$em->loadRelated($people, 'children')->loadRelated('pets')->loadRelated('specy')->loadRelated('eats');

(in fact implementation in PersistentCollection would be a simple return $this->em->loadRelated($this, $relations);)

As for your question, @Seldaek, about fetching the minimal dataset:
with partial {id} now being implemented (with all its dangers, but in our case, we start from an already hydrated collection, so partial won't create a partial entity),
that's quite near of a joinless select.

Why not using it to implement a less-than-perfect-but-API-stable loadRelated(),
and then have time to optimize it?

I've made my attempt at it at a pet project of mine,
it's a POC rather than a P.R. (all comments are in French, and I didn't even apply all of what I propose here)
… but I already have some promising results.

@outtersg commented on GitHub (Sep 10, 2023): Having exactly the same need, I was wondering if any official solution emerged and could allow closing the issue. Else I would be glad to participate, having a real use for it (junior developers that add 5-level "foreach"es, and senior developers being too few to recraft it and teach; so senior ones end up wanting to put some "easy" loadRelated()s, to avoid multi-minutes recursive fetching in production, and let themselves time to make junior ones become more careful, and then become more senior). @guilhermeblanco, regarding "The one to be implemented would be: $em->loadRelated()", wouldn't we want the _two_ to be implemented would be: $em->loadRelated() _and_ PersistentCollection->loadRelated()? This would allow syntactic sugar (avoid repeating $em), and chaining: ```php $em->loadRelated($people, 'children')->loadRelated('pets')->loadRelated('specy')->loadRelated('eats'); ``` (in fact implementation in PersistentCollection would be a simple `return $this->em->loadRelated($this, $relations);`) As for your question, @Seldaek, about fetching the minimal dataset: with `partial {id}` now being implemented (with all its dangers, but in our case, we start from an already hydrated collection, so `partial` won't create a partial entity), that's quite near of a joinless select. Why not using it to **implement a less-than-perfect-but-API-stable `loadRelated()`, and then have time to optimize it?** I've made my attempt at it at [a pet project of mine](https://github.com/outtersg/orme/blob/master/src/Doctrine/RelatedLoader.php), it's a POC rather than a P.R. (all comments are in French, and I didn't even apply all of what I propose here) … but I already have some promising results.
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: doctrine/archived-orm#2113