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, которые могут отрицательно сказаться на производительности.