java 如何在休眠中重用 Criteria 对象?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/368966/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-29 12:07:12  来源:igfitidea点击:

How to reuse a Criteria object with hibernate?

javahibernatespring-mvcpaginationdisplaytag

提问by agnul

I'm trying to do query result pagination with hibernate and displaytag, and Hibernate DetachedCriteriaobjects are doing their best to stand in the way. Let me explain...

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

The easiest way to do pagination with displaytag seems to be implementing the PaginatedListinterface that has, among others, the following methods:

使用 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();

I'm thinking of throwing my PaginatedList implementation a Criteria object and let it work along theese lines...

我正在考虑将我的 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());
}

But this doesn't work, because the addOrder()or the setProjection()calls modify the criteria object rendering it in-usable for the successive calls. I'm not entirely sure of the order of the calls, but the db throws an error on getFullListSize()trying to do a "select count(*) ... order by ..." which is obviously wrong.

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

I think I could fix this by creating an object of my own to keep track of query conditions and rebuilding the Criteria object for each call, but that feels like reinventing yet another wheel. Is there a smarter way, possibly copying the Criteria initially passed in and working on that copy?

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

Update: It looks like getListis called first, and getFullListSizeis called multiple times after, so, as soon as there's an ordering passed in, getFullListSizewill fail. It would make sense to hit the db only once (in getListI'd say) and cache the results, with no need to copy/reset the Criteriaobject, but still...

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

Update (again): Forget about that, once I've done the countI can't do the select, and vice versa. I really need two distinct Criteriaobjects.

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

采纳答案by james

well, DetachedCriteria are Serializable, so you have built-in (if inelegant) deep clone support. You could serialize the initial criteria to a byte[] once on construction, then deserialize it each time you want to use it.

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

回答by

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

Will effectively "reset" the criteria between the rowCount projection and execution of the criteria itself.

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

I would make sure your Order hasn't been added before doing the rowCount, it'll slow things down. My implementation of PaginatedList ALWAYS runs a count query before looking for results, so ordering isn't an issue.

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

回答by Min

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

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

In that post I spotted a CriteriaTransformer.clone method.

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

That should copy the criteria object.

那应该复制标准对象。

You can also set the projection on your getlist method.

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

Woops I didn't notice you were referring to java hibernate. Anyway, this http://forum.hibernate.org/viewtopic.php?t=939039

糟糕,我没有注意到您指的是 Java 休眠。无论如何,这个http://forum.hibernate.org/viewtopic.php?t=939039

forum post should be able to answer your question.

论坛帖子应该能够回答你的问题。

回答by agnul

Ugly as it may be I ended up using the serialization trick. I just serialize the DetachedCriteriaobject to a byte array on construction of the PaginatedListobject and de-serialize it when needed. Ouch.

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

回答by agnul

Another thing worth trying:

另一件值得尝试的事情:

implement a generic DAO like the one suggested on hibernate's siteand pass it to the PaginatedList object, along with a Restrictions object. The PaginatedList object would then do something like

实现一个像hibernate 站点上建议的那样通用 DAO ,并将它与一个 Restrictions 对象一起传递给 PaginatedList 对象。PaginatedList 对象然后会做类似的事情

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

and

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

Haven't tried that yet, but it should work.

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

回答by Marcin

There is a better and easy way to clone criteria, just simply:

有一种更好、更简单的方法来克隆标准,只需简单地:

ICriteria criteria = ...(your original criteria init here)...;

var criteriaClone = (ICriteria)criteria.Clone();

And getting back to Your problem. For pagination I've made a method, which gives me as a result:

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

1. Total rows count
2. Rows filtered by page & pageSize
In a single query to 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;

回答by bobac

public static DetachedCriteria Clone(this DetachedCriteria criteria)
{
   var dummy = criteria.ToByteArray();
   return dummy.FromByteArray<DetachedCriteria>();
}