4.4.4.4. Выполнение JPQL запросов
Для выполнения JPQL запросов предназначен интерфейс Query
, ссылку на который можно получить у текущего экземпляра EntityManager
вызовом метода createQuery()
. Если запрос предполагается использовать для извлечения сущностей, рекомендуется вызывать createQuery()
с передачей типа результата, что приведет к созданию TypedQuery
.
Методы Query
в основном соответствуют методам стандартного интерфейса JPA javax.persistence.Query
. Рассмотрим отличия.
-
setParameter()
- устанавливает значение параметра запроса. При передаче в данный метод экземпляра сущности выполняет неявное преобразование экземпляра в его идентификатор. Например:Customer customer = ...; TypedQuery<Order> query = entityManager.createQuery( "select o from sales$Order o where o.customer.id = ?1", Order.class); query.setParameter(1, customer);
Обратите внимание на сравнение в запросе по идентификатору, но передачу в качестве параметра самого экземпляра сущности.
Вариант метода с передачей
implicitConversions = false
не выполняет такого преобразования. -
setView()
,addView()
- устанавливают представление, используемое при загрузке данных. -
getDelegate()
- возвращает экземплярjavax.persistence.Query
, предоставляемый реализацией ORM.
При выполнении запроса через Query
изменения в текущем персистентном контексте не учитываются, т.е. запрос просто выполняется в БД. Если результатом выборки являются экземпляры, уже находящиеся в персистентном контексте, то в результате запроса окажутся именно они, а не прочитанные из БД. Ситуацию поясняет следующий фрагмент теста:
TypedQuery<User> query;
List<User> list;
query = em.createQuery("select u from sec$User u where u.name = ?1", User.class);
query.setParameter(1, "testUser");
list = query.getResultList();
assertEquals(1, list.size());
User user = list.get(0);
user.setName("newName");
query = em.createQuery("select u from sec$User u where u.name = ?1", User.class);
query.setParameter(1, "testUser");
list = query.getResultList();
assertEquals(1, list.size());
User user1 = list.get(0);
assertTrue(user1 == user);
Запросы, модифицирующие данные (update
, delete
) приводят к сбросу (flush) в базу данных текущего персистентного контекста перед выполнением. Другими словами, ORM сначала синхронизирует состояние сущностей в персистентном контексте и в БД, а уже потом выполняет модифицирующий запрос. Рекомендуется выполнять такие запросы в неизмененном персистентном контексте, чтобы исключить неявные действия ORM, которые могут отрицательно сказаться на производительности.