EntityManager em = ...;
CriteriaBuilder cb = em.getCriteriaBuilder();
Java Platform, Enterprise Edition (Java EE) 8 Учебник по Java EE |
Назад | Вперёд | Содержание |
Базовая семантика запроса Criteria состоит из предложений SELECT
, FROM
и необязательного WHERE
, аналогичных запросу JPQL. Запросы Criteria устанавливают эти предложения с использованием объектов Java, поэтому запрос может быть создан типобезопасным способом.
Здесь рассматриваются следующие темы:
Интерфейс javax.persistence.criteria.CriteriaBuilder
используется для создания
Запросов Criteria
Выбор
Выражения
Предикаты
Упорядочивание
Чтобы получить объект интерфейса CriteriaBuilder
, вызовите метод getCriteriaBuilder
объекта EntityManager
или EntityManagerFactory
.
В следующем коде показано, как получить объект CriteriaBuilder
с помощью метода EntityManager.getCriteriaBuilder
:
EntityManager em = ...;
CriteriaBuilder cb = em.getCriteriaBuilder();
Запросы Criteria строятся путём получения объекта следующего интерфейса:
javax.persistence.criteria.CriteriaQuery
Объекты CriteriaQuery
определяют конкретный запрос, который будет перемещаться по одному или нескольким объектам. Получите объекты CriteriaQuery
, вызвав один из методов CriteriaBuilder.createQuery
. Чтобы создать типобезопасные запросы, вызовите метод CriteriaBuilder.createQuery
следующим образом:
CriteriaQuery<Pet> cq = cb.createQuery(Pet.class);
Тип объекта CriteriaQuery
должен быть равен ожидаемому типу результата запроса. В предыдущем коде тип объекта установлен в CriteriaQuery<Pet>
для запроса, который найдёт объекты сущности Pet
.
Следующий фрагмент кода создаёт объект CriteriaQuery
для запроса, который возвращает String
:
CriteriaQuery<String> cq = cb.createQuery(String.class);
Для конкретного объекта CriteriaQuery
корневая сущность запроса, от которой происходит вся навигация, называется корнем запроса. Это похоже на предложение FROM
в запросе JPQL.
Создайте корень запроса, вызвав метод from
объекта CriteriaQuery
. Аргументом метода from
является либо класс сущности, либо объект EntityType<T>
для сущности.
Следующий код устанавливает сущность Pet
корнем запроса:
CriteriaQuery<Pet> cq = cb.createQuery(Pet.class);
Root<Pet> pet = cq.from(Pet.class);
Следующий код устанавливает класс Pet
корнем запроса, используя объект EntityType<T>
:
EntityManager em = ...;
Metamodel m = em.getMetamodel();
EntityType<Pet> Pet_ = m.entity(Pet.class);
Root<Pet> pet = cq.from(Pet_);
Запросы Criteria могут иметь несколько корней запросов. Обычно это происходит, когда запрос перемещается по нескольким объектам.
Следующий код имеет два объекта Root
:
CriteriaQuery<Pet> cq = cb.createQuery(Pet.class);
Root<Pet> pet1 = cq.from(Pet.class);
Root<Pet> pet2 = cq.from(Pet.class);
Для запросов, которые переходят к связанным классам сущностей, запрос должен определить соединение со связанной сущностью, вызвав один из методов From.join
у корневого объекта запроса или другого объекта соединения. Методы join
аналогичны ключевому слову JOIN
в JPQL.
Цель объединения использует класс Metamodel типа EntityType<T>
, чтобы указать персистентное поле или свойство присоединяемого объекта.
Методы join
возвращают объект типа Join<X, Y>
, где X
— исходная сущность, а Y
является целью объединения. В следующем фрагменте кода Pet
является исходной сущностью, Owner
— целью, а Pet_
— статически сгенерированным классом метамодели:
CriteriaQuery<Pet> cq = cb.createQuery(Pet.class);
Root<Pet> pet = cq.from(Pet.class);
Join<Pet, Owner> owner = pet.join(Pet_.owners);
Вы можете образовать цепочку объединений, чтобы перейти к связанным объектам целевой сущности, не создавая объект Join<X, Y>
для каждого объединения:
CriteriaQuery<Pet> cq = cb.createQuery(Pet.class);
Root<Pet> pet = cq.from(Pet.class);
Join<Owner, Address> address = pet.join(Pet_.owners).join(Owner_.addresses);
Объекты Path
, которые используются в предложениях SELECT
и WHERE
запроса Criteria, могут быть запросами корневых объектов, объектами объединения или другими объектами Path
. Используйте метод Path.get
, чтобы перейти к атрибутам сущностей запроса.
Аргументом метода get
является соответствующий атрибут класса метамодели сущности. Атрибут может быть либо однозначным атрибутом, указанным @SingularAttribute
в классе Metamodel, либо атрибутом со значением коллекции, указанным одним из @CollectionAttribute
, @SetAttribute
, @ListAttribute
или @MapAttribute
.
Следующий запрос возвращает имена всех домашних животных в хранилище данных. Метод get
вызывается у корня запроса pet
с атрибутом name
класса метамодели Pet_
сущности Pet
в качестве аргумента:
CriteriaQuery<String> cq = cb.createQuery(String.class);
Root<Pet> pet = cq.from(Pet.class);
cq.select(pet.get(Pet_.name));
Условия, которые устанавливаются путём вызова метода CriteriaQuery.where
, могут ограничивать результаты запроса к объекту CriteriaQuery
. Вызов метода where
аналогичен установке условия WHERE
в запросе JPQL.
Метод where
выполняет объекты интерфейса Expression
для ограничения результатов в соответствии с условиями выражений. Для создания объектов Expression
используются методы, определённые в интерфейсах Expression
и CriteriaBuilder
.
Объект Expression
используется в предложениях SELECT
, WHERE
или HAVING
запроса. Таблица 43-1 показывает условные методы, которые могут использоваться с объектами Expression
.
Таблица 43-1. Условные методы в интерфейсе Expression
Метод |
Описание |
|
Проверяет, является ли выражение null |
|
Проверяет, не является ли выражение null |
|
Проверяет, находится ли выражение в списке значений |
В следующем запросе используется метод Expression.isNull
, чтобы найти всех домашних животных, у которых атрибут color
равен null:
CriteriaQuery<Pet> cq = cb.createQuery(Pet.class);
Root<Pet> pet = cq.from(Pet.class);
cq.where(pet.get(Pet_.color).isNull());
В следующем запросе используется метод Expression.in
для поиска всех коричневых и чёрных питомцев:
CriteriaQuery<Pet> cq = cb.createQuery(Pet.class);
Root<Pet> pet = cq.from(Pet.class);
cq.where(pet.get(Pet_.color).in("brown", "black"));
Метод in
также может проверять, является ли атрибут членом коллекции.
Интерфейс CriteriaBuilder
определяет дополнительные методы для создания выражений. Эти методы соответствуют арифметическим, строковым операторам, операторам даты, времени, функции case и функциям JPQL. Таблица 43-2 показывает условные методы, которые могут использоваться с объектами CriteriaBuilder
.
Таблица 43-2. Условные методы в интерфейсе CriteriaBuilder
Условный метод |
Описание |
|
Проверяет, равны ли два выражения |
|
Проверяет, что два выражения не равны |
|
Проверяет, что первое числовое выражение больше второго |
|
Проверяет, что первое числовое выражение больше или равно второму |
|
Проверяет, что первое числовое выражение меньше второго |
|
Проверяет, что первое числовое выражение меньше или равно второму |
|
Проверяет, находится ли значение первого выражения между вторым и третьим выражениями |
|
Проверяет, соответствует ли выражение заданному шаблону |
В следующем коде используется метод CriteriaBuilder.equal
:
CriteriaQuery<Pet> cq = cb.createQuery(Pet.class);
Root<Pet> pet = cq.from(Pet.class);
cq.where(cb.equal(pet.get(Pet_.name), "Fido"));
В следующем коде используется метод CriteriaBuilder.gt
:
CriteriaQuery<Pet> cq = cb.createQuery(Pet.class);
Root<Pet> pet = cq.from(Pet.class);
Date someDate = new Date(...);
cq.where(cb.gt(pet.get(Pet_.birthday), date));
В следующем коде используется метод CriteriaBuilder.between
:
CriteriaQuery<Pet> cq = cb.createQuery(Pet.class);
Root<Pet> pet = cq.from(Pet.class);
Date firstDate = new Date(...);
Date secondDate = new Date(...);
cq.where(cb.between(pet.get(Pet_.birthday), firstDate, secondDate));
В следующем коде используется метод CriteriaBuilder.like
:
CriteriaQuery<Pet> cq = cb.createQuery(Pet.class);
Root<Pet> pet = cq.from(Pet.class);
cq.where(cb.like(pet.get(Pet_.name), "*do"));
Чтобы указать несколько условных предикатов, используйте методы составных предикатов интерфейса CriteriaBuilder
, как показано в таблице 43-3.
Таблица 43-3. Методы составных предикатов в интерфейсе CriteriaBuilder
Метод |
Описание |
|
Логическое AND двух булевых выражений |
|
Логическое OR двух булевых выражений |
|
Логическое отрицание данного булева выражения |
В следующем коде показано использование составных предикатов в запросах:
CriteriaQuery<Pet> cq = cb.createQuery(Pet.class);
Root<Pet> pet = cq.from(Pet.class);
cq.where(cb.equal(pet.get(Pet_.name), "Fido")
.and(cb.equal(pet.get(Pet_.color), "brown")));
Для запросов, которые возвращают более одного результата, часто полезно организовать эти результаты. Интерфейс CriteriaQuery
определяет следующие методы упорядочения и группировки:
Метод orderBy
упорядочивает результаты запроса в соответствии с атрибутами объекта
Метод groupBy
группирует результаты запроса вместе в соответствии с атрибутами объекта, а метод having
ограничивает эти группы в соответствии с условием
Здесь рассматриваются следующие темы:
Чтобы упорядочить результаты запроса, вызовите метод CriteriaQuery.orderBy
, передав объект Order
. Чтобы создать объект Order
, вызовите метод CriteriaBuilder.asc
или CriteriaBuilder.desc
. Метод asc
используется для упорядочивания результатов по возрастанию значения переданного параметра выражения. Метод desc
используется для упорядочивания результатов по убыванию значения переданного параметра выражения. Следующий запрос показывает использование метода desc
:
CriteriaQuery<Pet> cq = cb.createQuery(Pet.class);
Root<Pet> pet = cq.from(Pet.class);
cq.select(pet);
cq.orderBy(cb.desc(pet.get(Pet_.birthday)));
В этом запросе результаты будут упорядочены по дню рождения питомца от наивысшего к низшему. То есть домашние животные, рождённые в декабре, появятся в результатах выборки раньше домашних животных, рождённых в мае.
Следующий запрос показывает использование метода asc
:
CriteriaQuery<Pet> cq = cb.createQuery(Pet.class);
Root<Pet> pet = cq.from(Pet.class);
Join<Owner, Address> address = pet.join(Pet_.owners).join(Owner_.address);
cq.select(pet);
cq.orderBy(cb.asc(address.get(Address_.postalCode)));
В этом запросе результаты будут упорядочены по почтовому индексу владельца домашнего животного от самого низкого до самого высокого. То есть домашние животные, владелец которых живёт по почтовому индексу 10001, появятся в результатах выборки раньше домашних животных, владелец которых живёт по почтовому индексу 91000.
Если в orderBy
передаётся более одного объекта Order
, приоритет определяется порядком их появления в списке аргументов orderBy
. Первый объект Order
имеет приоритет.
Следующий код упорядочивает результаты по нескольким критериям:
CriteriaQuery<Pet> cq = cb.createQuery(Pet.class);
Root<Pet> pet = cq.from(Pet.class);
Join<Pet, Owner> owner = pet.join(Pet_.owners);
cq.select(pet);
cq.orderBy(cb.asc(owner.get(Owner_.lastName)), owner.get(Owner_.firstName)));
Результаты этого запроса будут упорядочены в алфавитном порядке по фамилии владельца домашнего животного, а затем по имени.
Метод CriteriaQuery.groupBy
разделяет результаты запроса на группы. Чтобы установить эти группы, передайте выражение для groupBy
:
CriteriaQuery<Pet> cq = cb.createQuery(Pet.class);
Root<Pet> pet = cq.from(Pet.class);
cq.groupBy(pet.get(Pet_.color));
Этот запрос возвращает все сущности Pet
и группирует результаты по цвету питомца.
Используйте метод CriteriaQuery.having
в сочетании с groupBy
для фильтрации групп. Метод having
принимает условное выражение в качестве параметра, ограничивает результат запроса в соответствии с условным выражением:
CriteriaQuery<Pet> cq = cb.createQuery(Pet.class);
Root<Pet> pet = cq.from(Pet.class);
cq.groupBy(pet.get(Pet_.color));
cq.having(cb.in(pet.get(Pet_.color)).value("brown").value("blonde"));
В этом примере запрос группирует возвращённые сущности Pet
по цвету, как в предыдущем примере. Однако единственными возвращаемыми группами будут объекты Pet
, для атрибута color
которых установлено значение brown
или blonde
. То есть домашние животные серого цвета не попадут в результаты запроса.
Чтобы подготовить запрос к выполнению, создайте объект TypedQuery<T>
с типом результата запроса, передав объект CriteriaQuery
в EntityManager.createQuery
.
Чтобы выполнить запрос, вызовите getSingleResult
или getResultList
для объекта TypedQuery<T>
.
Используйте метод TypedQuery<T>.getSingleResult
для выполнения запросов, которые возвращают один результат:
CriteriaQuery<Pet> cq = cb.createQuery(Pet.class);
...
TypedQuery<Pet> q = em.createQuery(cq);
Pet result = q.getSingleResult();
Используйте метод TypedQuery<T>.getResultList
для выполнения запросов, которые возвращают коллекцию объектов:
CriteriaQuery<Pet> cq = cb.createQuery(Pet.class);
...
TypedQuery<Pet> q = em.createQuery(cq);
List<Pet> results = q.getResultList();
Назад | Вперёд | Содержание |