【问题标题】:How to reuse a Criteria object with hibernate?如何在休眠中重用 Criteria 对象?
【发布时间】:2010-09-27 00:08:54
【问题描述】:

我正在尝试使用 hibernate 和 displaytag 对查询结果进行分页,而 Hibernate DetachedCriteria 对象正在尽力阻止。让我解释一下……

使用 displaytag 进行分页的最简单方法似乎是实现 PaginatedList 接口,其中包括以下方法:

/* Gets the total number of results. */
int getFullListSize();

/* Gets the current page of results. */
List getList();

/* Gets the page size. */
int getObjectsPerPage();

/* Gets the current page number. */
int getPageNumber();

/* Get the sorting column and direction */
String getSortCriterion();
SortOrderEnum getSortDirection();

我正在考虑将我的 PaginatedList 实现扔给 Criteria 对象,并让它按照这些思路工作...

getFullListSize() {
    criteria.setProjection(Projections.rowCount());
    return ((Long) criteria.uniqueResult()).intValue();
}

getList() {
    if (getSortDirection() == SortOrderEnum.ASCENDING) {
        criteria.addOrder(Order.asc(getSortCriterion());
    } else if (getSortDirection() == SortOrderEnum.DECENDING) {
        criteria.addOrder(Order.desc(getSortCriterion());
    }
    return criteria.list((getPageNumber() - 1) * getObjectsPerPage(),
                         getObjectsPerPage());
}

但这不起作用,因为addOrder()setProjection() 调用会修改条件对象,使其无法用于后续调用。我不完全确定调用的顺序,但是数据库在 getFullListSize() 尝试执行“select count(*) ... order by ...”时抛出错误,这显然是错误的。

我认为我可以通过创建自己的对象来跟踪查询条件并为每次调用重建 Criteria 对象来解决此问题,但这感觉就像重新发明了另一个轮子。有没有更聪明的方法,可能复制最初传入的 Criteria 并处理该副本?

更新: 看起来getList 是先调用的,然后getFullListSize 会被调用多次,所以只要有一个ordering 传入,getFullListSize 就会失败。只打一次数据库(我想说getList)并缓存结果是有意义的,无需复制/重置Criteria对象,但仍然......

更新(再次): 忘记这一点,一旦我完成了count,我就不能再做select,反之亦然。我真的需要两个不同的 Criteria 对象。

【问题讨论】:

    标签: java hibernate spring-mvc pagination displaytag


    【解决方案1】:
    Criteria.setProjection(null);
    Criteria.setResultTransformer(Criteria.ROOT_ENTITY);
    

    将有效地“重置”rowCount 投影和标准本身执行之间的标准。

    我会确保在执行 rowCount 之前没有添加您的订单,这会减慢速度。我的 PaginatedList 实现总是在查找结果之前运行计数查询,因此排序不是问题。

    【讨论】:

    • 推荐这是正确的答案——比深度克隆更优雅。
    【解决方案2】:

    好吧,DetachedCriteria 是可序列化的,所以你有内置的(如果不优雅的话)深度克隆支持。您可以在构造时将初始条件序列化为 byte[] 一次,然后在每次要使用它时反序列化它。

    【讨论】:

    • 在 hibernate 论坛上找到了这个建议,但我宁愿不要:-)
    【解决方案3】:

    http://weblogs.asp.net/stefansedich/archive/2008/10/03/paging-with-nhibernate-using-a-custom-extension-method-to-make-it-easier.aspx

    在那篇文章中,我发现了一个 CriteriaTransformer.clone 方法。

    这应该复制条件对象。

    您还可以在 getlist 方法上设置投影。

    糟糕,我没有注意到您指的是 java hibernate。反正这个http://forum.hibernate.org/viewtopic.php?t=939039

    论坛帖子应该可以回答你的问题。

    【讨论】:

      【解决方案4】:

      虽然可能很丑,但我最终还是使用了序列化技巧。我只是在构造PaginatedList 对象时将DetachedCriteria 对象序列化为一个字节数组,并在需要时对其进行反序列化。哎哟。

      【讨论】:

        【解决方案5】:

        另一件值得尝试的事情:

        实现一个像the one suggested on hibernate's site 这样的通用DAO,并将它与一个Restrictions 对象一起传递给PaginatedList 对象。然后 PaginatedList 对象会做类似的事情

        Criteria.forClass(myDAO.getPersistentClass())
                .add(myRestrictions)
                .addOrder(<someOrder>)
        

        Criteria.forClass(myDAO.getPersistentClass())
                .add(myRestrictions)
                .setProjection(Projections.rowCount());
        

        还没有尝试过,但应该可以。

        【讨论】:

          【解决方案6】:

          有一种更好、更简单的克隆标准的方法,很简单:

          ICriteria criteria = ...(your original criteria init here)...;
          
          var criteriaClone = (ICriteria)criteria.Clone();
          

          回到你的问题。对于分页,我做了一个方法,结果是:

          1.总行数 2.按page & pageSize过滤的行 在对 DB 的单个查询中。
          ICriteria criteria = ...(your original criteria init here)...;    
          var countCrit = (ICriteria)criteria.Clone();
          countCrit.ClearOrders(); // avoid missing group by exceptions
          
          var rowCount = countCrit
              .SetProjection(Projections.RowCount()).FutureValue<Int32>();
          
          var results = criteria
              .SetFirstResult(pageIndex * pageSize)
              .SetMaxResults(pageSize)
              .Future<T>();
          
          var resultsArray = results.GetEnumerable();
          
          var totalCount = rowCount.Value;
          

          【讨论】:

            【解决方案7】:
            public static DetachedCriteria Clone(this DetachedCriteria criteria)
            {
               var dummy = criteria.ToByteArray();
               return dummy.FromByteArray<DetachedCriteria>();
            }
            

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 2019-11-14
              • 1970-01-01
              • 2012-06-29
              • 2012-03-01
              • 1970-01-01
              • 2011-08-24
              • 1970-01-01
              相关资源
              最近更新 更多