Поддержка Querydsl в Spring Data Commons

В статье, посвящённой автоматической генерации запросов в Spring Data Commons, я упоминал о двух проблемах такого подхода: статичность запросов и одновременное отсутствие типобезопасности.  Одно из решений этой проблемы — библиотека , которая позволяет строить запросы к данным (кстати не только JPA запросы) используя java в качестве языка описания запросов.

Подготовка

Querydsl своей реализацией отчасти похож на JPA Metamodel. Сущности, определённые в проекте, сканируются и для них создаются вспомогательные классы. Поэтому, помимо добавления артефакта Querydsl в зависимости, требуется так же добавить и плагин для генерации вспомогательных классов.

Разумеется, надо не забыть добавить в зависимости Spring Data JPA, сам Spring и какую-нибудь реализацию JPA.

Интерфейс QueryDslPredicateExecutor

Чтобы включить поддержку Querydsl в генерируемый репозиторий, необходимо чтоб он имел в списке предков интерфейс QueryDslPredicateExecuter<T>, где T — тип сущности, с которой работает репозиторий. При этом, даже если планируется работать только с Querydsl, наличие в предках интерфейса Repository или любого из его наследников всё равно является обязательным.

Интерфейс QueryDslPredicateExecutor<T> определяет несколько методов:

  • T FindOne(Predicate) — возвращает один объект, соответствующий условия
  • Iterable<T> findAll(Predicate) — возвращает несколько объектов, соответствующих условию. Обратите внимание, что возвращается всегда Iterable<T>, без возможности уточнить тип
  • long count(Predicate) — возвращает количество объектов в базе данных, соответствующих условию
  • boolean exists(Predicate) — сообщает, есть ли в базе данных объект соответствующий условию

Все методы принимают условие Querydsl.

Предикаты в Querydsl

Написание запросов в Querydsl настолько просто, что достаточно показать пример и сразу всё станет ясно:

QPerson и QPassport выше — специальные вспомогательные типы Querydsl, коорые были сгенерированы из описаний сущностией (а сами сущности я взял из вводной статьи о Spring Data Commons). Querydsl плагин автоматически создаёт классы с префиксом Q для каждого найденного им класса сущности. Внутри такого Q* класса содержится единственный глобальный объект этого класса, на основе которого уже и делаются запросы. У объекта Q* класса есть все публичные поля, которые есть у сущности, из которой он был сгенерирован. Но, в этих полях не содержится значений, у них есть методы, описывающие, какими должны быть значения поля. В примере выше я строю запрос, который требует, чтобы поле firstName сущности Person имело значение «Test».

Благодаря использованию вспомогательных классов запросы, написанные с помощью Querydsl, типобезопасны и проверяются на стадии компиляции. А создание запросов методом вызова java функций позволяет создавать динамические запросы во время исполнения.

Возможных условий в Querydsl великое множество и все они перечислены в документации. Я лишь отмечу, что их достаточно для любого практического применения:

Обращение к полям классов, на которые ссылается сущность, реализуется весьма интуитивно:

Кроме того, условия можно комбинировать, использовать объединения и так далее:

Метод and(), равно как методы or(), any() и другие, принимает в себя любой объект типа Predicate, что позволяет изменять части запроса во время исполнения.

Код примера доступен на github.