I am using hibernate-orm with spring-data-jpa. I have three entities A
, B
, C
declared as following
@Entity
public class A {
@OneToMany(....)
List<B> listOfB;
}
@Entity
public class B {
@ManyToOne(...)
private A a;
@OneToMany(...)
private C listOfC;
}
@Entity
public class C {
@ManyToOne(...)
private B b;
}
My objective is to get A
and fetch listOfB
as well, with some condition on entity C
without fetching it. The following JPQL is working fine
SELECT a FROM A a
LEFT JOIN FETCH a.listOfB b
LEFT JOIN b.listOfC c
WHERE c.xyz = :xyz
When i tried using JPA Specification my Specification looks like following
(rootA, query, builder) -> {
Fetch fetch = rootA.fetch(A_.listOfB, JoinType.LEFT);
ListJoin listJoin = fetch.join(B_.listOfC)
return builder.equal(listJoin.get(C_.xyz), xyz);
}
So i am re-using the implicit join done by the fetch operation. This join is not working in specification. It’s outputting the following JPQL
SELECT a FROM A a
LEFT JOIN FETCH a.listOfB b
WHERE c.xyz = :xyz
Saying that, there is no c
alias.
I have looked into hibernate github source code. Found out that, there is a class named QueryStructure.java
responsible for generating JPQL query from the criteria object.
I found the function renderFetches which render the fetches
@SuppressWarnings({ "unchecked" })
private void renderFetches(
StringBuilder jpaqlQuery,
RenderingContext renderingContext,
Collection<? extends Fetch> fetches) {
if ( fetches == null ) {
return;
}
for ( Fetch fetch : fetches ) {
( (FromImplementor) fetch ).prepareAlias( renderingContext );
jpaqlQuery.append( renderJoinType( fetch.getJoinType() ) )
.append( "fetch " )
.append( ( (FromImplementor) fetch ).renderTableExpression( renderingContext ) );
renderFetches( jpaqlQuery, renderingContext, fetch.getFetches() );
}
}
Similarly there is a function renderJoins
responsible for all the joins.
These two are recursive functions rendering the criteria object tree.
It’s clear that all the joins inside the fetches are ignored. There is no call to function renderJoins
inside from renderFetches
which causes the generated query to be incomplete.
Is there any in depth reason why we are not joining inside from a fetch ? If yes then how could i re-use the existing implicit joins done by fetch ?
Thanks in advance.