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调试并比较生成的查询,可以非常清楚地看到这里发生的事情。
使用相当简单的Sale
→ Item
一对多映射(希望不言自明),基于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; }
另一种解决方案如下:
- 运行你的
criteria.list()
而不设置任何别名=>根实体的引用集/列表将填充代理=>这里你正确设置了最大结果等 - 在同一个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请求。 让我们希望有人来找并解决它:)