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