它是Hibernate的有效行为(JPQL Query,OneToMany)

时间:2016-05-11 13:15:10

标签: hibernate jpa hql jpql

我有两个实体,比如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不应该执行额外的查询来加载它们吗?

2 个答案:

答案 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集合。