在我的应用程序中,我有一个实体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是数据库中A的元组数)。
我非常惊讶的是,对于急切的提取,Hibernate并没有直接进行LEFT JOIN查询。
所以我首先尝试使用Hibernate的注释@Fetch(FetchMode.JOIN)
,但它没有按预期工作。
所以我使用以下附加说明转换了我的列表查询:
Join<A,B> joinAB = critRoot.join(A_.BEntries, JoinType.LEFT);
joinAB.join(B_.cValue, JoinType.LEFT);
好的,现在生成的SQL查询包含了所有需要的LEFT JOIN来热切地构建完整的A对象......但是它仍然在B表上执行其他N个查询!
我首先想到的是它来自我在Bentries参数上的@OrderBy
注释,但即使被删除,它仍然在进行N + 1选择而不是1 ...
知道为什么它会像这样吗?...甚至为什么默认情况下它不会在实体中急切获取的集合中进行LEFT JOIN?