Как повторно использовать объект Criteria в спящем режиме?

StackOverflow https://stackoverflow.com/questions/368966

Вопрос

Я пытаюсь выполнить разбиение на страницы результатов запроса с помощью 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 ВСЕГДА выполняет запрос подсчета перед поиском результатов, поэтому порядок не является проблемой.

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.В любом случае, это 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>();
}
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top