EAGER works only on one level, and it is not intended to receive tree structures.
I suggest you change the one-to-many choice to LAZY, because choosing EAGER is the smell of code and choosing a root entity is:
SELECT e FROM MyEntity e LEFT JOIN FETCH e.children where e.parent is null
You use recursion to get the whole graph with additional subsamples.
void fetchAll(MyEntity root) { for(MyEntity child : root.children) { fetchAll(child); } }
A more efficient approach is to completely remove the children’s collection and use the recursive CTE in the FK association to retrieve all the identifiers of all objects in a given tree. Then, with the second JPA request, you retrieve all the objects by their identifiers and restore the tree corresponding to the parents .
Update using an actual solution
I added a test on GitHub to provide a solution for this. Given the following object:
@Entity(name = "Node") public class Node { @Id @GeneratedValue private Long id; @ManyToOne @JoinColumn(name = "parent_id") private Node parent;
The next transformer can restore the whole tree as you want
Node root = (Node) doInHibernate(session -> { return session .createSQLQuery( "SELECT * " + "FROM Node " + "CONNECT BY PRIOR id = parent_id " + "START WITH parent_id IS NULL ") .addEntity(Node.class) .setResultTransformer(new ResultTransformer() { @Override public Object transformTuple(Object[] tuple, String[] aliases) { Node node = (Node) tuple[0]; if(node.parent != null) { node.parent.addChild(node); } return node; } @Override public List transformList(List collection) { return Collections.singletonList(collection.get(0)); } }) .uniqueResult(); });
source share