Entities as below:
class A {
Long id;
@ManyToMany
@JoinTable(name = "rel_a_b", joinColumns = @JoinColumn(name = "a_id"), inverseJoinColumns = @JoinColumn(name = "b_id"))
Set<B> bSet;
}
class B {
Long id;
@ManyToMany(mappedBy = "bSet")
Set<A> aSet;
@ManyToMany
@JoinTable(name = "rel_b_c", joinColumns = @JoinColumn(name = "b_id"), inverseJoinColumns = @JoinColumn(name = "c_id"))
Set<C> cSet;
}
class C {
Long id;
@ManyToMany(mappedBy = "cSet")
Set<B> bSet;
}
I need to select A
entities and join fetch bSet
and cSet
in B
entity. Using JPA Criteria, codes as below:
final Fetch<A, B> bSetFetch = rootA.fetch("bSet", JoinType.LEFT);
bSetFetch.fetch("cSet", JoinType.LEFT);
are working perfectly, but I can't achieve this with QueryDSL. I tried
final QA a = QA.a;
jpaQuery
.from(a)
.leftJoin(a.bSet, QB.b).fetchJoin()
.leftJoin(QB.b.cSet).fetchJoin()
.select(a)
but it throws exception that
query specified join fetching, but the owner of the fetched association was not present in the select list [FromElement{explicit,not a collection join,fetch join,fetch non-lazy properties,classAlias=b,role=A.b,tableName=`b`,tableAlias=b4_,origin=a a2_,columns={a2_.id ,className=B}}] [select a
from A a
left join fetch a.bSet as b
left join fetch b.cSet]]
, if without fetchJoin()
, the results don't include bSet
and cSet
. Could anyone solve this?
The fetch joins are applied correctly from a QueryDSL point of view. We can also observe this from the fact that the produced JPQL query looks correct.
The limitation here is that Hibernate only allows FETCH JOINS if the owner of the fetch association is projected in the select clause. cSet
is an association on B
, so you would need to project your b
's or omit the fetch join for cSet
. For example:
jpaQuery
.from(a)
.leftJoin(a.bSet, QB.b).fetchJoin()
.leftJoin(QB.b.cSet).fetchJoin()
.select(a, b)
Now this will result in duplicate results for a
due to the cardinality of bSet
. That is just a limitation of fetch joins in Hibernate.
Alternatively, you could consider specifying a fetch graph for the query:
EntityGraph postGraph = em.getEntityGraph("post");
query.setHint("javax.persistence.fetchgraph", postGraph);
For more information on using EntityGraphs see https://www.baeldung.com/jpa-entity-graph