我有两个实体,比如A和B,映射如下:
public class A{
...
@OneToMany(mappedBy = "a", cascade = CascadeType.ALL)
Set<B> bs
}
public class B{
...
String someProp;
...
@ManyToOne
@JoinColumn(name = "A_ID")
A a
}
A的某个实体实例在数据库中有两个B元素。
当我执行A的简单查询时:
entityManager.createQuery("SELECT a FROM A a WHERE a.id = 1").getSingleResult();
并且一切都按预期工作,我在Set中有两个B实例,但是当我执行查询时:
Query query = entityManager.createQuery("SELECT a FROM A a JOIN FETCH a.bs b WHERE b.someProp= :somePropParam");
query.setParameter("somePropParam","somePropValue");
query.getResultList();
我在集合中有一个B的元素(我要求的元素)。
我修改了查询:
entityManager.createQuery("SELECT b.a FROM B b JOIN b.a a WHERE b.someProp = :somePropParam.. more a conditions );
//.... this query works.
不应该先查询加载B的所有实例吗? Hibernate不应该执行额外的查询来加载它们吗?
答案 0 :(得分:1)
这是预期的行为。这是一个常见的陷阱。 getSingleResult方法返回第一行。如果当然有多个B,则结果集包含多个条目,但您只获得第一个条目。这看起来有点奇怪。
但是将它看作是一个带有setMaxResult(1)和经典sql连接的普通Query。它最终会得到相同的结果。这也是如果你使用渴望提取,hibernate使用子关系的子选择的原因。
如果您期望大量子数据请求具有额外查询的子项并避免1:n双向映射。从父母到孩子的关系应该有充分的理由,因为从长远来看,它往往会导致问题。
其他示例请考虑以下内容。 您使用您的查询和setMaxResult(10)。保证您获得父项的10个条目的潜在结果集大小是无限的。因此,hibernate没有任何机会请求正确数量的数据。这可以导致获取大量数据而不需要它。
答案 1 :(得分:1)
为:
生成的SQL Query query = entityManager.createQuery("SELECT a FROM A a JOIN FETCH a.bs b WHERE b.someProp= :somePropParam");
query.setParameter("somePropParam","somePropValue");
query.getResultList();
如下:
select /** columns from a and b **/
from A a inner join A b on a.id=b.a_id
where b.someProp='someProperty'
这是正确的SQL结果根据条件(返回1行)IT告诉我“是的,有一个A实现你得到的条件,你在这里”,但我认为有“JOIN FETCH a.bs”我迫使Hiberante急切加载所有“bs”集合,即使第一个查询没有返回元素。我认为Hibernate执行额外的查询,如
SELECT b。* FROM B b WHERE b.a_id =(上面的查询返回的id)。
在A中建立完整的B集合。