它是 Hibernate 的有效行为吗(JPQL 查询,OneToMany)

Is it valid behavior of Hibernate (JPQL Query , OneToMany)

我有两个实体 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();

一切都按预期工作,我在集合中得到了一个实例和两个 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();

我得到了 A 的实例和集合中 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 不应该执行额外的查询来加载它们吗?

这是预期的行为。这是一个常见的陷阱。方法getSingleResult returns 第一行。如果有多个 B 当然结果集包含多个条目,但你只会得到第一个。这可能看起来有点奇怪。

但将其视为带有 setMaxResult(1) 和经典 sql 连接的普通查询。它最终会得到相同的结果。如果您使用急切获取,这也是为什么 hibernate 对 child 关系使用子选择的原因。

如果您希望有大量 child 数据,请使用额外查询请求 child 并避免 1:n bi-directional 映射。从 parent 到 child 的关系应该有充分的理由,因为它通常会导致长 运行.

中的问题

考虑以下其他示例。 您使用查询和 setMaxResult(10)。保证您获得 parent 的 10 个条目的潜在结果集大小是无限的。所以休眠将没有任何机会请求正确数量的数据。这可能导致在不需要的情况下获取大量数据。

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'

根据条件(返回 1 行)它是正确的 SQL 结果 IT 告诉我 "Yes there is one instance of A fulfiling the condition you get, here you are",但我认为具有“JOIN FETCH a.bs”我强制 Hiberante 加载所有"bs" 即使第一个查询没有返回元素,也急切地收集。我认为 Hibernate 会执行其他查询,例如

SELECT b.* FROM B b WHERE b.a_id = (上面查询返回的id).

在 A 中构建完整的 B 集合。