它是 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 集合。
我有两个实体 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 集合。