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

它是否是Hibernate的有效行为(JPQL查询,OneToMany),hibernate,jpa,hql,jpql,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 } 一切正常,我得到了一个集合中有两个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
}
一切正常,我得到了一个集合中有两个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的A实例(我请求的元素)

我修改了查询:

 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返回第一行。如果有多个B,那么结果集当然包含多个条目,但您只得到第一个条目。这似乎有点奇怪

但可以将其视为带有setMaxResult(1)和经典sql连接的普通查询。结果也是一样的。这也是为什么hibernate使用子选择(subselect)处理子关系的原因,如果您使用的是急切抓取(eager fetching)

如果需要大量子数据,请使用额外的查询请求子数据,并避免1:n双向映射。父母和孩子之间的关系应该有很好的理由,因为从长远来看,这往往会导致问题

另外的例子考虑如下。


使用查询和setMaxResult(10)。保证您获得10个父项的潜在结果集大小是无限的。因此hibernate将没有机会请求正确数量的数据。这可能导致在不需要数据的情况下获取大量数据

这是预期的行为。这是一个常见的陷阱。方法getSingleResult返回第一行。如果有多个B,那么结果集当然包含多个条目,但您只得到第一个条目。这似乎有点奇怪

但可以将其视为带有setMaxResult(1)和经典sql连接的普通查询。结果也是一样的。这也是为什么hibernate使用子选择(subselect)处理子关系的原因,如果您使用的是急切抓取(eager fetching)

如果需要大量子数据,请使用额外的查询请求子数据,并避免1:n双向映射。父母和孩子之间的关系应该有很好的理由,因为从长远来看,这往往会导致问题

另外的例子考虑如下。 使用查询和setMaxResult(10)。保证您获得10个父项的潜在结果集大小是无限的。因此hibernate将没有机会请求正确数量的数据。这可能导致在不需要数据的情况下获取大量数据

为以下对象生成的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结果。它告诉我“是的,有一个实例满足您得到的条件,您在这里”,但我认为有了“JOIN FETCH A.bs”,我强制Hibernate急切地加载所有“bs”集合,即使第一次查询没有返回元素。我以为Hibernate会执行额外的查询,比如

从b中选择b.*,其中b.a_id=(上面的查询返回的id)

要在生成的SQL中构建完整的Bs集合,请执行以下操作:

    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结果。它告诉我“是的,有一个实例满足您得到的条件,您在这里”,但我认为有了“JOIN FETCH A.bs”,我强制Hibernate急切地加载所有“bs”集合,即使第一次查询没有返回元素。我以为Hibernate会执行额外的查询,比如

从b中选择b.*,其中b.a_id=(上面的查询返回的id)


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

如果返回的A(由任何返回类型为A的查询返回)的集合中确实有2个元素,那么当您访问返回对象的集合字段时,您应该始终找到2个元素。我认为它应该在A的“B”集合中返回2个元素,但它只返回一个,由于它是通过在a.id=b.a\U id上选择a和b中的`/**列**/从a内部联接a b返回的,其中b.someProp='someProperty'`没有额外的查询来加载额外的b表行,这不符合条件
b.someProp='someProperty'
,这可能是“预期行为”在Hibernate中,但肯定不是在其他实现中…如果返回的A(由任何返回类型为A的查询返回)的集合中确实有2个元素,那么当您访问返回对象的集合字段时,您应该始终找到2个元素。我认为它应该返回A的“bs”集合中的2个元素,但它只返回一个,由于它是通过在a.id=b.a\U id上选择a和b中的`/**列**/从a内部联接a b返回的,其中b.someProp='someProperty'`没有额外的查询来加载额外的b表行,这不符合条件
b.someProp='someProperty'
,这可能是“预期行为”在Hibernate中,但肯定不在其他实现中……它应该这样做。这不应该。没有