首页 > 解决方案 > JPA Specification join on fetch 不起作用(Hibernate,Spring Data JPA)

问题描述

我正在使用带有 spring-data-jpa 的 hibernate-orm。我有三个实体A, BC声明如下:

@Entity
public class A {
    @OneToMany(....)
    private List<B> listOfB;
}
@Entity
public class B {
     @ManyToOne(...)
     private A a;
    @OneToMany(...)
    private List<C> listOfC;
}
@Entity
public class C {
    @ManyToOne(...)
    private B b;
}

我的目标是获取A和获取listOfB以及实体上的某些条件C而不获取它。以下 JPQL 工作正常。

SELECT a FROM A a
LEFT JOIN FETCH a.listOfB b
LEFT JOIN b.listOfC c
WHERE c.xyz = :xyz

当我尝试使用 JPA 规范时,我的规范如下所示:

(rootA, query, builder) -> {
    Fetch fetch = rootA.fetch(A_.listOfB, JoinType.LEFT);
    ListJoin listJoin = ((ListJoin)fetch).join(B_.listOfC)
   return builder.equal(listJoin.get(C_.xyz), xyz);
}

我正在重用 fetch 操作完成的隐式连接。此联接在规范中不起作用。它正在输出以下 JPQL。

SELECT a FROM A a
LEFT JOIN FETCH a.listOfB b
WHERE c.xyz = :xyz

说起来,没有c别名。

我查看了 Hibernate GitHub 源代码。我发现,有一个名为QueryStructure.java负责从条件对象生成 JPQL 查询的类。

我找到了渲染提取的函数renderFetches

@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() );
        }
    }

同样,有一个函数renderJoins负责所有的连接。

这两个是渲染标准对象树的递归函数。

很明显,提取中的所有连接都被忽略了。renderJoins内部没有函数调用renderFetches导致生成的查询不完整。

为什么我们不从 fetch 中加入内部有什么深入的原因吗?如果是,那么我如何重用 fetch 完成的现有隐式连接?

使用休眠测试用例模板重新生成此问题。

标签: javaspringhibernatespring-data-jpacriteria-api

解决方案


正如我在问题中提到的,没有renderJoins来自内部的调用,renderFetches在末尾添加以下内容renderFetches可以解决问题。

if (fetch instanceof From) {
    From from = (From) fetch;
    renderJoins(jpaqlQuery, renderingContext, from.getJoins());
}

我在hibernate-orm中给出了PR HHH-14916

PR 已合并将在下一个5.6.x 版本中提供。


推荐阅读