Вы только что видели, как манипулировать сущностями по отдельности, используя API-интерфейс EntityManager. Вы уже знаете, как искать сущность по идентификатору, удалять ее, обновлять ее атрибуты и т. д. Однако поиск сущности по идентификатору довольно сильно ограничивает вас, поскольку вы можете извлечь только одну сущность, используя ее уникальный идентификатор. На практике вам может потребоваться извлечь сущность, исходя из иных критериев (имени, ISBN-номера и т. д.), либо извлечь набор сущностей на основе других критериев (например, все сущности, связанные с клиентами, проживающими в США). Эта возможность присуща реляционным базам данных, а у JPA есть язык, который обеспечивает это взаимодействие, — JPQL.
JPQL предназначен для определения поисков постоянных сущностей, которые не зависят от основной базы данных. JPQL — это язык запросов, укоренившийся в синтаксисе SQL. Он является стандартным языком для выполнения запросов к базам данных. Однако основное отличие состоит в том, что при использовании SQL вы получаете результаты в виде строк и столбцов (таблиц), а в случае применения JPQL — в виде сущности или коллекции сущностей. Синтаксис JPQL является объектно-ориентированным и, следовательно, более легким для понимания разработчиками, чей опыт ограничивается объектно-ориентированными языками. Разработчики управляют своей доменной моделью сущностей, а не структурой таблицы, используя точечную нотацию (например, myClass.myAttribute).
«За кулисами» JPQL применяет механизм отображения для преобразования JPQL-запросов в такие, которые будут понятны базам данных SQL. Запрос выполняется в отношении основной базы данных с использованием SQL- и JDBC-вызовов, после чего следует присваивание значений атрибутам экземпляров сущностей и их возврат приложению — все происходит очень простым и эффективным образом с применением богатого синтаксиса запросов.
Самый простой JPQL-запрос обеспечивает выборку всех экземпляров одной сущности:
SELECT b
FROM Book b
Если вы знаете SQL, то этот код должен показаться вам знакомым. Вместо выборки из таблицы JPQL производит выборку сущностей, в данном случае той, что носит имя Book. Кроме того, используется оператор FROM для наделения сущности псевдонимом: b является псевдонимом Book. Оператор SELECT запроса указывает на то, что типом результата запроса является сущность b (Book). Выполнение этого оператора приведет к получению списка, в который будет входить нуль или более экземпляров Book.
Чтобы ограничить результаты, добавьте критерии поиска. Вы можете воспользоваться оператором WHERE, как показано далее:
SELECT b
FROM Book b
WHERE b.title = 'H2G2'
Псевдоним предназначен для навигации по атрибутам сущности с применением оператора-точки. Поскольку сущность Book обладает постоянным атрибутом, носящим имя title и тип String, b.title ссылается на атрибут title сущности Book. Выполнение этого оператора приведет к получению списка, в который будет входить нуль или более экземпляров Book со значением title в виде H2G2.
Самый простой запрос на выборку состоит из двух обязательных частей — операторов SELECT и FROM. SELECT определяет формат результатов запроса. Оператор FROM определяет сущность или сущности, из которых будут получаться результаты, а необязательные операторы WHERE, ORDER BY, GROUP BY и HAVING могут быть использованы для ограничения или упорядочения результатов запроса. Листинг 6.20 демонстрирует упрощенный синтаксис JPQL-оператора.
SELECT <оператор SELECT>
FROM <оператор FROM>
[WHERE <оператор WHERE>]
[ORDER BY <оператор ORDER BY>]
[GROUP BY <оператор GROUP BY>]
[HAVING <оператор HAVING>]
Листинг 6.20 определяет оператор SELECT, а операторы DELETE и UPDATE также могут быть использованы для выполнения операций удаления и обновления в отношении множественных экземпляров заданного класса-сущности.
SELECT
Оператор SELECT придерживается синтаксиса выражений путей и приводит к результату в одной из следующих форм: сущность, атрибут сущности, выражение-конструктор, агрегатная функция или их последовательность. Выражения путей являются строительными блоками запросов и используются для перемещения по атрибутам сущности или связям сущностей (либо коллекции сущностей) с помощью точечной (.) навигации с применением следующего синтаксиса:
SELECT [DISTINCT] <выражение> [[AS] <идентификационная переменная>]
expression::= { NEW | TREAT | AVG | MAX | MIN | SUM | COUNT }
Простой оператор SELECT возвращает сущность. Например, если сущность Customer содержит псевдоним c, то SELECT возвратит сущность или список сущностей:
SELECT c
FROM Customer c