Hibernate Criteria API

Начиная с версии 5.0 собственный Criteria API признан устаревшим и не развивается. Вместо него рекомендуется использовать JPA Criteria API.

Начиная с версии 5.2 Hibernate Criteria API объявлен deprecated и не рекомендуется к использованию

why-do-i-hate-hibernate-13-638Несмотря на вышесказанное страшное предупреждение, родной (устаревший) Criteria API мне нравится больше и кажется более выразительным (и менее типобезопасным, да).

Criteria API это механизм, позволяющий описывать запросы к базе данных используя java код и java объекты. Тем самым это решает проблему генерации запросов исходя из состояния программы.Например, мы заранее не знаем, захочет пользователь фильтровать клиенов по возрасту или не захочет. В случае использования HQL или SQL запросов мы вынуждены будем либо писать два варианта запроса, либо модифицировать код запроса (то есть править текст) во время исполнения. В Criteria API это решается простым условным вызовом метода.

Простые запросы

Все запросы в данном примере основываются на модели данных использованной ранее в примерах HQL и SQL.

Для начала запросим список объектов какого-нибудь класса:

Запрос выше полностью аналогичен запросу HQL "from Person". С Criteria также работают и все те вещи, которые работают и с Query: пейджинг, таймауты и т.д.

Разумеется, в Criteria запросах можно и нужно накладывать условия, по которым объекты будут отбираться:

Существует множество вариантов ограничений, аналогичных тем, что встречаются в SQL: .eq(), .like() , .between(), .in(), .ge() и т.д. Кроме того, вызовы .not() , .and() и .or() (и более сложные, вроде .disjunction()) позволяют делать логические операции над ограничениями:

И поскольку задание условий запроса реализуется просто вызовами функций, речь уже не идёт о поддержки параметризованных запросов. Вы просто передаёте значения в функции, а Hibernate делает всё остальное сам.

Связи и коллекции

Сущности в Hibernate могут иметь связи и отношения друг с другом. И на этим связи и отношения можно ссылаться в Criteria API:

Так в примере выше выбираю все сущности класса Passport и накладываю условие на его поле owner, которое ссылается на класс Person, поле lastName которого и ограничивается условием.

Точно так же можно обратиться и к другой стороне связи, той, где используется коллекция:

Запросы по примеру

Запросы по примеру выбирают объекты, которые аналогичны заданному:

При формировании непосредственного запроса в базу у объекта образца игнорируются null поля, поля с @Id, поля ассоциаций, поле serialVersionUUID. Дополнительно можно задать, как в примере выше, игнорирование регистра строк, использование like для сравнения строк, список дополнительно исключаемых полей и т.д.

DetachedCriteria

Обычно Criteria создаётся в рамках какой-то конкретной сесии и существует в пределах её persistence context. Однако можно создать Criteria, которая не будет привязана к конкретной Session и не присоединена (detached) к persistence context и может быть, в дальнейшем, использована с любым объектом Session. Отчасти таковое поведение напоминает именованные запросы.

DetachedCriteria определяется так же, как обычная Criteria, с той лишь разницей, что её нельзя исполнить. Затем, когда появляется подходящая Session вызовом getExecutableCriteria()  DetachedCriteria преобразуется в обычную Criteria, связанную с этой Session и исполняется.

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