Как повторно использовать объект Criteria в спящем режиме?
-
21-08-2019 - |
Вопрос
Я пытаюсь выполнить разбиение на страницы результатов запроса с помощью 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 для каждого вызова, но это похоже на изобретение еще одного колеса.Есть ли более разумный способ — скопировать первоначально переданные критерии и работать над этой копией?
Обновлять:Это выглядит как getList
вызывается первым, и getFullListSize
после этого вызывается несколько раз, поэтому, как только будет передано упорядочение, getFullListSize
не удастся.Имеет смысл попасть в БД только один раз (в getList
Я бы сказал) и кэшировать результаты без необходимости копировать/сбрасывать Criteria
объект, но все же...
Обновление (еще раз):Забудь об этом, как только я закончу count
я не могу сделать select
, и наоборот.мне действительно нужны два разных Criteria
объекты.
Решение
ну, DetachedCriteria являются сериализуемыми, поэтому у вас есть встроенная (хотя и неэлегантная) поддержка глубокого клонирования.Вы можете сериализовать исходные критерии в byte[] один раз при создании, а затем десериализовать их каждый раз, когда захотите их использовать.
Другие советы
Criteria.setProjection(null);
Criteria.setResultTransformer(Criteria.ROOT_ENTITY);
Будет эффективно «сбрасывать» критерии между проекцией rowCount и выполнением самого критерия.
Я хотел бы убедиться, что ваш заказ не был добавлен, прежде чем выполнять rowCount, это замедлит работу.Моя реализация PaginatedList ВСЕГДА выполняет запрос подсчета перед поиском результатов, поэтому порядок не является проблемой.
В этом посте я заметил метод CriteriaTransformer.clone.
Это должно скопировать объект критериев.
Вы также можете установить проекцию для своего метода getlist.
Упс, я не заметил, что вы имели в виду спящий режим Java.В любом случае, это http://forum.hibernate.org/viewtopic.php?t=939039
Сообщение на форуме должно быть в состоянии ответить на ваш вопрос.
Как бы уродливо это ни было, в итоге я применил трюк с сериализацией.Я просто сериализую DetachedCriteria
объект в массив байтов при построении PaginatedList
объект и десериализовать его при необходимости.Ой.
Еще одна вещь, которую стоит попробовать:
реализовать общий DAO, например тот, который предложен на сайте hibernate и передайте его объекту PaginatedList вместе с объектом Restrictions.Тогда объект PaginatedList сделает что-то вроде
Criteria.forClass(myDAO.getPersistentClass())
.add(myRestrictions)
.addOrder(<someOrder>)
и
Criteria.forClass(myDAO.getPersistentClass())
.add(myRestrictions)
.setProjection(Projections.rowCount());
Еще не пробовал, но должно сработать.
public static DetachedCriteria Clone(this DetachedCriteria criteria)
{
var dummy = criteria.ToByteArray();
return dummy.FromByteArray<DetachedCriteria>();
}