Criteria API返回的结果集太小

时间:2010-02-02 11:28:21

标签: 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();

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

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


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

5 个答案:

答案 0 :(得分:9)

通过在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)的差异。像ResultTransformer这样的DISTINCT_ROOT_ENTITY是一个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()不存在,我只是做了它起来。也许它应该!

答案 1 :(得分:2)

答案 2 :(得分:1)

另一种解决方案如下:

  1. 运行您的criteria.list()而不设置任何别名=>将使用proxies =>填充根实体的引用集/列表。在这里你正确设置了最大结果等
  2. 在同一个hibernate session =>中自行运行别名条件上述代理将被初始化
  3. 这样的事情:

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

    希望这可以提供帮助,
    斯泰恩

答案 3 :(得分:1)

希望这可以提供帮助

public List<Employee> getData(int to, int from) {

    Criteria hCriteria = null;
    List<Employee> viewDataList = null;
    List<Employee> 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;
}

答案 4 :(得分:0)

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

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