Подтвердить что ты не робот

Как повторно использовать объект 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.

4b9b3361

Ответ 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>();
}