1

在我的应用程序中,我有一个实体 A 和一个实体 B 的列表,应该急切地获取:

@Entity
public class A
{
    ...
    /* @OrderBy("cValue.id ASC") */
    @OneToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL)
    @JoinColumn(name="A_ID", nullable=false)
    private List<B> BEntries = new ArrayList<B>();
    ...
}

@Entity
public class B
{
    ...
    @ManyToOne
    @JoinColumn(name = "C_ID", nullable = false)
    private C cValue;
    ...
}

为了得到 A 的列表,我首先做了这个简单的查询:

CriteriaBuilder critBuilder = em.getCriteriaBuilder();
CriteriaQuery<A> critQuery = critBuilder.createQuery(A.class);
Root<A> critRoot = critQuery.from(A.class);
critQuery.select(critRoot);

但是在那里我看到 Hibernate 在数据库上执行 N+1 选择查询,在 A 类上执行 1 个选择查询,在 B 类上执行 N(其中 N 是 DB 中 A 的元组数)。

令我惊讶的是,对于 Eager fetch,Hibernate 没有直接执行 LEFT JOIN 查询。

所以我首先尝试使用@Fetch(FetchMode.JOIN)Hibernate的注解,但是并没有按预期工作。

因此,我使用以下附加说明转换了我的列表查询:

Join<A,B> joinAB = critRoot.join(A_.BEntries, JoinType.LEFT);
joinAB.join(B_.cValue, JoinType.LEFT);

好的,现在生成的 SQL 查询包含所有需要的 LEFT JOIN 以急切地构建完整的 A 对象......但它仍在 B 表上执行其他 N 个查询!我首先认为它来自@OrderBy我在 Bentries 参数上添加的注释,但即使删除,它仍然在进行 N+1 选择而不是 1...

知道为什么它会这样吗?...甚至为什么默认情况下它不对实体中急切地获取的集合进行 LEFT JOIN ?

4

0 回答 0