Criteria API 返回的结果集太小

发布于 2024-08-20 03:29:59 字数 664 浏览 12 评论 0原文

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

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!

我不明白定义最大结果后结果集大小如何变小,因为行数小于定义的最大值。这确实看起来像一个错误,或者休眠中是否又存在一些我不知道的奇怪方面?


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

How is this possible, I have to following criteria

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

The size of list is now 20. If I add a max results to the criteria,

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

.. now list's size is 18!

I don't understand how the resultsets size can be smaller after defining the max results, as the amount of rows is smaller than the defined max. This sure seems like a bug, or is there again some weird aspects of hibernate that I'm not aware of?


If you're looking for an answer to this question, make sure to read the accepted answer and its comments.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

星光不落少年眉 2024-08-27 03:30:00

希望这可以有所帮助

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

Hope this can be help

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;
}
风情万种。 2024-08-27 03:30:00

另一个解决方案如下:

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

如下所示:

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;

希望这可以有所帮助,
斯泰因

Another solution is the following:

  1. run your criteria.list() without setting any alias => the referenced sets/list of the root entity will be filled with proxies => here you set correctly the max results and such
  2. run the alias criteria on its own in the same hibernate session => the above proxies will be initialized

Something like this:

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;

Hope this can help,
Stijn

强者自强 2024-08-27 03:30:00

这是休眠中的一个已知问题。查看@Cowan 生成的 SQL 和问题的解释。他们的 jira 中有一个针对此问题的开放错误请求。希望有人能解决这个问题:)

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

This is a known problem in hibernate. Look at @Cowan for a generated SQL and an explanation of the problem. There is an open bug request for this in their jira. Let's hope that someone comes along and fixes it :)

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

酒几许 2024-08-27 03:29:59

通过在 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_ENTITYResultTransformer 是一个 Java 类,它在执行 SQL 后处理 SQL 行的结果。因此,当您指定 maxResults 时,它将用作 SQL 的行限制; SQL 包含对Collection 中元素的联接,因此您将 SQL 结果限制为 90 个子元素。应用 DISTINCT_ROOT_ENTITY 转换器后,可能会导致根元素少于 20 个,这完全取决于 90 个连接结果中哪个根元素恰好首先出现。

HQL 中的 DISTINCT 的行为非常不同,因为它实际上使用 SQL DISTINCT 关键字,该关键字在行限制之前应用。因此,这会按照您的预期运行,并解释了两者之间的差异。

理论上,您应该查看 setProjection 以在 SQL 级别应用投影 - 类似 c.setProjection( Projections.distinct(Projections.rootEntity())) - 但不幸的是 Projections.rootEntity() 不存在,我只是编造了它。或许应该如此!

What is happening here can be seen very clearly by turning on SQL debugging in Hibernate and comparing the generated queries.

Using a fairly simple SaleItem one-to-many mapping (which is hopefully self-explanatory), a Criteria-based query like this:

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

produces SQL like this:

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

whereas a Query like this:

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

produces something like:

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

Note the difference in the very first line (DISTINCT). A ResultTransformer like DISTINCT_ROOT_ENTITY is a Java class, which processes the results of the SQL rows after the SQL is executed. Therefore, when you specify a maxResults, that will be applied as a row limit on the SQL; the SQL includes a join onto the elements in the Collection, so you're limiting your SQL result to 90 sub-elements. Once the DISTINCT_ROOT_ENTITY transformer is applied, that may result in less than 20 root elements, purely dependent on which root elements happen to come out first in the 90 joined results.

DISTINCT in HQL behaves very differently, in that that actually uses the SQL DISTINCT keyword, which is applied before the row limit. Therefore, this behaves as you expect, and explains the difference between the 2.

In theory you should be looking at setProjection to apply a projection at the SQL level -- something like c.setProjection(Projections.distinct(Projections.rootEntity())) -- but unfortunately Projections.rootEntity() doesn't exist, I just made it up. Perhaps it should!

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文