Как стать автором
Обновить

Комментарии 22

Можно ж в SQL написать .... ((:val IS NULL) OR (column = :val)).... В функцию передаем или null или значение.

Можно, конечно, но, если параметров станет не 3, а например, как в серьезном интернет-магазине, под пол сотни штук, то может получиться огромный сложный запрос с кучей джойнов и операторов.

ИМХО: Проще будет найти и внести изменения в java код, чем в огромный sql-запрос.

да не, вполне читаемая конструкция будет.

Только с or могут индексы ломаться, я обычно делаю

case when :id is null then true else :id=id end

Ну и так хоть сотню, нет больших проблем.

Оптимизатор запроса видит условия еще перед выполнением и просто выкидывает не нужные ветки (в отличие от or)

А чем CriteriaApi и Specification лучше данного подхода? Я, конечно понимаю, что мы все условия заворачиваем в спеки и основной сервис худеет засчет сервиса спецификаций.

Но по сути, это ровным счетом такая же дичь с теми же if-else, только реализация через еще более громоздкий синтаксис и без половины возможностей обычного SQL.

Имхо, hibernate вообще крайне неудачный выбор если мы хотим строить динамические запросы.

В таких случаях мы либо идем в сторону нативного SQL и StringBuilder, либо выбираем что-нибудь попроще. Например EBean.

Можно, мы так и делаем. Во всяких отчетах, где нет возможности оперировать запросом, только так.

Но такой стиль плохо на производительность влияет. Впрочем, в универсальных запросах с условиями по разным полям с производительностью и так все плохо.

В postgres, например, при таком запросе не отрабатывает индекс, насколько я помню, и будет всегда полный перебор

Если ты смотришь по набору полей, то БД возьмет индекс в котором присутствует ровно такой же набор полей

Использование StringBuilder для построения динамических SQL запросов больше похоже на антипаттерн, потому что:

  1. Это сложно поддерживать, читать и отлаживать. Если у вас изменится какое-либо поле или название параметра - все эти изменения необходимо будет отслеживать и править вручную. И если вы это упустите, то заметите в лучшем случае, только во время интеграционных тестов (если они есть =)) или что хуже - это выстрелит только на проде. При использовании того же Criteria API с Hibernate Static Metamodel Generator, все ошибки вы увидите уже во время компиляции.

  2. Отсутствие проверки типов данных. Можно сказать что тоже относится к первому пункту.

  3. Когда вы собираете строки вручную есть потенциальная вероятность SQL инъекций.

Если вам не нравится Criteria API и вы хотите работать со строками, вы можете использовать тот же JOOQ. На самом же деле есть множество готовых решений для построения динамических SQL запросов: Criteria API, Querydsl, jOOQ, MyBatis и т.д.

Честно говоря, все эти решения имеют те или иные проблемы. Ну или ограничения, если хотите. Например, решения типа JOOQ предполагают, что у вас при компиляции структура базы такая же, как в проме. С одной стороны, вроде бы это плюс (вы примерно об этом пишете в п.1), а с другой - это далеко не всегда просто обеспечить. Просто потому, что база с которой вы работаете, может быть не ваша, и изменения в ее схему вносятся другой командой. Ну или вы просто заранее ничего не знаете про базу вообще, кроме того что она существует, и всю ее структуру можете добыть только при запуске, но не ранее.

Кажется для этих целей в JPA существует интерфейс Specification

Нет, спеки существуют в spring-data-jpa. К стандарту они не имеют никакого отношения.

А как же быть с индексами? Необходимо прояснить этот вопрос.

В рамках статьи рассматривактся вопрос сборки селекта, а не архитектура БД.

В реальном проекте, где в таблице много записей, нет смысла делать такие запросы без проработки вопроса с индексами. На малом количестве записей это работать будет, но в реальном проекте - оч. сомневаюсь

Простите, но это адская дичь. Есть же Specification. Берем CriteriaBuilder, берем входную DTO-шку и формируем при помощи и на основе их нормальный, красивый запрос.

Чёрт с ними, со спеками. Тут вопрос более другой: за какой такой надобностью нужно собирать sql-запрос вместо jpql/hql?

Есть ощущение что мало людей знает про Specification. Недавно только делал подобное на спеках, возможно стоит пнуть себя и написать статью.

Да ещё QueryByExample

А если ещё освоить Static Metamodel, то получим compile-time проверки при рефакторинге классов сущностей.

Два замечания. Нативный запрос (если я не ошибаюсь) выдает результат без помещения объектов в контекст, что может давать проблемы при использовании этих запросов в одной транзакции с нормальными jpa jpql запросами. Это надо учитывать.

Второе, хотелось бы подробное исследование по универсальным запросам - как сделать так, чтобы универсальные запросы по разным полями адекватно использовали индексы?

Народ, кто-нибудь сталкивался с Specification + Projection? По фильтру нужно получить не саму сущность, а её проекцию

Зарегистрируйтесь на Хабре, чтобы оставить комментарий