Criteria API返回的结果集太小

Kim*_*m L 14 java hibernate criteria hibernate-criteria

这怎么可能,我必须遵循标准

Criteria criteria = getSession().createCriteria(c);
criteria.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY);
criteria.add(Restrictions.eq("active",true));
List list = criteria.list();

列表的大小现在是20.如果我在条件中添加最大结果,

Criteria criteria = getSession().createCriteria(c);
criteria.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY);
criteria.setMaxResults(90);
criteria.add(Restrictions.eq("active",true));
List list = criteria.list();
Run Code Online (Sandbox Code Playgroud)

..现在列表的大小是18!

在定义最大结果后,我不明白结果集大小如何更小,因为行数小于定义的最大值.这肯定看起来像一个bug,或者还有一些我不知道的hibernate奇怪的方面?


如果您正在寻找这个问题的答案,请务必阅读接受的答案及其评论.

Cow*_*wan 9

通过在Hibernate中打开SQL调试并比较生成的查询,可以非常清楚地看到这里发生的事情.

使用一个相当简单的SaleItem一对多映射(希望是不言自明的),Criteria基于a 的查询如下:

Criteria c = sessionFactory.getCurrentSession().createCriteria(Sale.class);
c.createAlias("items", "i");
c.add(Restrictions.eq("i.name", "doll"));
c.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY);
c.setMaxResults(2);
Run Code Online (Sandbox Code Playgroud)

像这样产生SQL:

select top ? this_.saleId as saleId1_1_, ... 
from Sale this_ 
inner join Sale_Item items3_ on this_.saleId=items3_.Sale_saleId 
inner join Item items1_ on items3_.items_id=items1_.id 
where items1_.name=?
Run Code Online (Sandbox Code Playgroud)

Query像这样:

Query q = sessionFactory.getCurrentSession().createQuery("select distinct s from Sale s join s.items as i where i.name=:name");
q.setParameter("name", "doll");
q.setMaxResults(2);
Run Code Online (Sandbox Code Playgroud)

产生类似的东西:

select top ? distinct hibernated0_.saleId as saleId1_ 
from Sale hibernated0_ 
inner join Sale_Item items1_ on hibernated0_.saleId=items1_.Sale_saleId 
inner join Item hibernated2_ on items1_.items_id=hibernated2_.id 
where hibernated2_.name=?
Run Code Online (Sandbox Code Playgroud)

注意第一行(DISTINCT)中的差异.甲ResultTransformerDISTINCT_ROOT_ENTITY是一个Java类,该处理SQL行的结果之后被执行的SQL.因此,当您指定a maxResults时,将作为SQL的行限制应用; SQL包含对元素的连接Collection,因此您将SQL结果限制为90 个子元素.一旦DISTINCT_ROOT_ENTITY变压器被施加,可能导致低于20个元素,完全取决于其根元素碰巧第一出来在90接合结果.

DISTINCT在HQL中表现的方式非常不同,因为它实际上使用了SQL DISTINCT关键字,它在行限制之前应用.因此,这表现得如您所愿,并解释了2之间的区别.

理论上你应该考虑在setProjectionSQL级别应用一个投影 - 类似于c.setProjection(Projections.distinct(Projections.rootEntity()))- 但遗憾的Projections.rootEntity()是不存在,我只是编造了它.也许它应该!

  • 对于寻找这个问题答案的人,我通过使用两个查询来解决方法.首先,我有我的正常标准,我想要的所有限制和限制,但增加了投影标准.setProjection(Projections.distinct(Projections.id())); 根据这个标准,我得到了一个我想要获取的pojos的列表.在此之后,我使用Restrictions.in("id",ids)创建了另一个标准; 第二个条件包含DISTINCT_ROOT_ENTITY,但不包含setMaxResult(因为它应用于第一个查询). (5认同)