Hibernate-orm joins on fetch not working

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.

Hibernate test case template is created in support of this issue.

This issue is also reported into hibernate issue tracker HHH-14916

Thanks for the report and test. If you could provide a PR against hibernate-orm with the test and a fix, that would be very helpful!

Either way, beware that this might alter the fetched objects which can lead to data deletion. That’s why it is not easily possible to do this kind of stuff.

Hi @beikov

I have created a pull request. I have also included test cases. Please review my pull request.

I could not move the ticket HHH-14916 into In Progress because of the permission requirement to move the issue.