Хороший вопрос. Вот что я делал в прошлом (многие вещи, о которых вы уже упоминали):
- Проверьте, присутствует ли предложение SELECT .
- Если это не так, добавьте
select count(*)
- В противном случае проверьте, есть ли в нем DISTINCT или агрегатные функции. Если вы используете ANTLR для разбора вашего запроса, возможно обойти это, но это довольно сложно. Скорее всего, вам лучше просто обернуть все это в
select count(*) from ()
.
- Удалить
fetch all properties
- Удалите
fetch
из объединений, если вы анализируете HQL как строку. Если вы действительно разбираете запрос с помощью ANTLR, вы можете полностью удалить left join
; это довольно грязно, чтобы проверить все возможные ссылки.
- Удалить
order by
- В зависимости от того, что вы сделали в 1.2, вам нужно будет удалить / настроить
group by
/ having
.
Вышеуказанное относится, естественно, к HQL. Для запросов Criteria вы весьма ограничены тем, что вы можете сделать, потому что это не поддается легкому манипулированию. Если вы используете какой-либо слой-обертку поверх Критериев, вы получите эквивалент (ограниченный) поднабор результатов анализа ANTLR и в этом случае можете применить большинство из перечисленного выше.
Так как вы обычно держитесь за смещение вашей текущей страницы и общее количество, я обычно запускаю фактический запрос с заданным лимитом / смещением в первую очередь и запускаю запрос count(*)
, только если количество возвращаемых результатов больше или равно для ограничения AND смещение равно нулю (во всех других случаях я либо запускаю count(*)
раньше, либо получаю все результаты обратно в любом случае). Конечно, это оптимистичный подход в отношении одновременных изменений.
Обновление (при ручной сборке HQL)
Мне не особенно нравится такой подход. При отображении в качестве именованного запроса HQL имеет преимущество проверки ошибок во время сборки (ну, технически, во время выполнения, потому что SessionFactory должен быть собран, хотя это обычно делается во время интеграционного тестирования). При генерировании во время выполнения происходит сбой во время выполнения :-) Выполнение оптимизации производительности также не совсем просто.
Конечно, те же рассуждения применимы и к Критериям, но из-за четко определенного API-интерфейса немного сложнее ошибиться, чем к конкатенации строк. Построение двух HQL-запросов параллельно (постраничный один и один «глобальный счет») также приводит к дублированию кода (и, возможно, к большему количеству ошибок) или заставляет вас написать какой-нибудь слой-обертку поверх этого, чтобы сделать это за вас. Оба пути далеки от идеальных. И если вам нужно сделать это из клиентского кода (как в over API), проблема становится еще хуже.
Я на самом деле немного размышлял по этому вопросу. API поиска из Hibernate-Generic-DAO кажется разумным компромиссом; в моем ответе на приведенный выше вопрос есть более подробная информация.