29

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

使用 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 对象来解决这个问题,但这感觉就像重新发明了另一个轮子。有没有更聪明的方法,可能复制最初传入的标准并处理该副本?

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

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

4

7 回答 7

49
Criteria.setProjection(null);
Criteria.setResultTransformer(Criteria.ROOT_ENTITY);

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

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

于 2009-09-24T16:59:29.073 回答
3

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

于 2008-12-15T17:59:15.267 回答
2

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

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

于 2008-12-15T19:21:17.677 回答
1

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

于 2008-12-17T11:58:10.330 回答
0

另一件值得尝试的事情:

实现一个通用 DAO,就像hibernate 网站上建议的那样,并将它与 Restrictions 对象一起传递给 PaginatedList 对象。然后 PaginatedList 对象将执行类似的操作

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

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

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

于 2009-04-30T07:55:20.913 回答
0

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

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;
于 2020-04-15T08:30:40.180 回答
-1
public static DetachedCriteria Clone(this DetachedCriteria criteria)
{
   var dummy = criteria.ToByteArray();
   return dummy.FromByteArray<DetachedCriteria>();
}
于 2010-07-17T10:44:46.687 回答