Как повторно использовать объект Criteria с гибернацией?
Я пытаюсь выполнить разбиение на результат с помощью 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()
изменяют объект-критерий, который делает его доступным для последовательных вызовов. Я не совсем уверен в порядке вызовов, но db выдает ошибку на getFullListSize()
, пытаясь сделать "select count(*) ... order by ...
", что явно неверно.
Я думаю, что могу исправить это, создав собственный объект, чтобы отслеживать условия запроса и перестраивать объект Criteria для каждого вызова, но это похоже на повторное создание еще одного колеса. Есть ли более разумный способ, возможно, скопировав исходный критерий Крит и работающий над этой копией?
Обновление:
Похоже, что getList
вызывается первым, а getFullListSize
вызывается несколько раз после этого, поэтому, как только происходит передача заказа, getFullListSize
завершится с ошибкой. Было бы разумно ударить db только один раз (в getList
я бы сказал) и кэшировать результаты, без необходимости копировать /reset объект Criteria
, но все же...
Обновить (снова):
Забудьте об этом, как только я сделал count
, я не могу сделать select
и наоборот. Мне действительно нужны два разных объекта Criteria
.
Ответы
Ответ 1
хорошо, DetachedCriteria - Serializable, поэтому у вас есть встроенная (если неэлегантная) поддержка глубокого клонирования. Вы можете сериализовать исходные критерии на байт [] один раз при построении, а затем десериализовать его каждый раз, когда хотите его использовать.
Ответ 2
Criteria.setProjection(null);
Criteria.setResultTransformer(Criteria.ROOT_ENTITY);
Будет эффективно "reset" критерий между проекцией rowCount и выполнением самих критериев.
Я сделал бы, чтобы ваш заказ не был добавлен до выполнения rowCount, это замедлит работу. Моя реализация PaginatedList ALWAYS запускает запрос подсчета перед поиском результатов, поэтому упорядочение не является проблемой.
Ответ 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.
Woops Я не заметил, что вы ссылались на спящий режим java. Во всяком случае, это http://forum.hibernate.org/viewtopic.php?t=939039
Сообщение форума должно быть в состоянии ответить на ваш вопрос.
Ответ 4
Уродливо, как может быть, я использовал трюк сериализации. Я просто сериализую объект DetachedCriteria
в массив байтов при построении объекта PaginatedList
и де-сериализую его, когда это необходимо. Уч.
Ответ 5
Еще одна вещь, которую стоит попробовать:
реализовать общий DAO, например тот, который предлагается на сайте hibernate, и передать его объекту PaginatedList вместе с объектом Restrictions. Объект PaginatedList будет делать что-то вроде
Criteria.forClass(myDAO.getPersistentClass())
.add(myRestrictions)
.addOrder(<someOrder>)
и
Criteria.forClass(myDAO.getPersistentClass())
.add(myRestrictions)
.setProjection(Projections.rowCount());
Еще не пробовал, но он должен работать.
Ответ 6
public static DetachedCriteria Clone(this DetachedCriteria criteria)
{
var dummy = criteria.ToByteArray();
return dummy.FromByteArray<DetachedCriteria>();
}