Как повторно использовать объект Criteria с Hibernate? - PullRequest
26 голосов
/ 15 декабря 2008

Я пытаюсь разбить результат на страницы запроса с помощью 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 объекта.

Ответы [ 6 ]

47 голосов
/ 24 сентября 2009
Criteria.setProjection(null);
Criteria.setResultTransformer(Criteria.ROOT_ENTITY);

Эффективно "сбросит" критерии между проекцией rowCount и выполнением самих критериев.

Я бы удостоверился, что ваш ордер не был добавлен перед выполнением rowCount, это замедлит работу. Моя реализация PaginatedList ВСЕГДА запускает запрос подсчета перед поиском результатов, поэтому упорядочение не является проблемой.

2 голосов
/ 15 декабря 2008

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 hibernate. Во всяком случае, это http://forum.hibernate.org/viewtopic.php?t=939039

сообщение на форуме должно быть в состоянии ответить на ваш вопрос.

2 голосов
/ 15 декабря 2008

хорошо, DetachedCriteria является Serializable, поэтому у вас есть встроенная (если не элегантная) поддержка глубокого клонирования. Вы можете сериализовать начальные критерии для байта [] один раз при создании, а затем десериализовать его каждый раз, когда захотите его использовать.

1 голос
/ 17 декабря 2008

Ужасно, но, может быть, я использовал трюк сериализации. Я просто сериализовал объект DetachedCriteria в байтовый массив при создании объекта PaginatedList и десериализовал его при необходимости. Уч.

0 голосов
/ 17 июля 2010
public static DetachedCriteria Clone(this DetachedCriteria criteria)
{
   var dummy = criteria.ToByteArray();
   return dummy.FromByteArray<DetachedCriteria>();
}
0 голосов
/ 30 апреля 2009

Еще одна вещь, которую стоит попробовать:

реализует общий DAO, такой как , предложенный на сайте hibernate , и передает его объекту PaginatedList вместе с объектом Restrictions. Объект PaginatedList будет тогда делать что-то вроде

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

и

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

Еще не пробовал, но должно работать.

...