Criteria API返回的结果集太小

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

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(); 

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

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


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

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

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

 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); 

像这样产生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=? 

而像这样的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); 

产生类似于:

 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=? 

注意第一行( DISTINCT )的差异。 像DISTINCT_ROOT_ENTITY这样的ResultTransformer是一个Java类,它在执行SQL 之后处理SQL行的结果。 因此,当您指定maxResults时,它将作为SQL的行限制应用; SQL包含对Collection元素的连接,因此您将SQL结果限制为90 个子元素 。 一旦应用了DISTINCT_ROOT_ENTITY变换器,这可能导致少于20个根元素,完全取决于90个连接结果中首先出现的根元素。

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

理论上你应该看看setProjection在SQL级别应用一个投影 – 比如c.setProjection(Projections.distinct(Projections.rootEntity())) – 但不幸的是, Projections.rootEntity()不存在,我刚刚成功。 也许它应该!

setMaxResults不适用于外连接SQL查询。 也许这是你的问题: Hibernate不会为一个集合启用外连接提取的查询返回不同的结果(即使我使用distinct关键字)? 。

希望这可以提供帮助

 public List getData(int to, int from) { Criteria hCriteria = null; List viewDataList = null; List exactDataList = null; try { hSession = HibernateSessionFactory.getSession(); hTransaction = hSession.beginTransaction(); hCriteria = hSession.createCriteria(Employee.class); /* hCriteria.setFirstResult(to); hCriteria.setFirstResult(from); */ hCriteria.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY); viewDataList = hCriteria.list(); // for limit exactDataList=viewDataList.subList(from,to); hTransaction.commit(); } catch (Exception e) { hTransaction.rollback(); } finally { try { hSession.flush(); HibernateSessionFactory.closeSession(); } catch (Exception hExp) { } } return exactDataList; } 

另一种解决方案如下:

  1. 运行你的criteria.list()而不设置任何别名=>根实体的引用集/列表将填充代理=>这里你正确设置了最大结果等
  2. 在同一个hibernate会话中自己运行别名标准=>上面的代理将被初始化

像这样的东西:

 Criteria criteria = this.getSession().createCriteria(User.class); criteria.setResultTransformer(CriteriaSpecification.ROOT_ENTITY); criteria.setMaxResults(10); // First get the results without joining with the other tables List results = criteria.list(); // at this point the set roles is filled with proxies // we'll now create and execute the join so these proxies are filled since we're still in the same session getSession().createCriteria(User.class, "u") .createAlias("u.roles", "r", CriteriaSpecification.LEFT_JOIN) .list(); return results; 

希望这可以帮助,
斯泰恩

这是hibernate中的一个已知问题。 查看@Cowan获取生成的SQL以及问题的解释。 在他们的jira中有一个开放的bug请求。 让我们希望有人来找并解决它:)

https://hibernate.atlassian.net/browse/HB-520