Для выполнения JPQL запросов предназначен интерфейс Query, ссылку на который можно получить у текущего экземпляра EntityManager вызовом метода createQuery(). Если запрос предполагается использовать для извлечения сущностей, рекомендуется вызывать createQuery() с передачей типа результата, что приведет к созданию TypedQuery.
Методы Query в основном соответствуют методам стандартного интерфейса
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()- аналогичны одноименным методам интерфейсаEntityManager- устанавливают представление, используемое при загрузке данных текущим запросом, не влияя на представление всегоEntityManager. -
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);Такое поведение определяется параметром openjpa.IgnoreChanges=true, заданным в файле
persistence.xml
базового проекта cuba. В прикладном проекте данный параметр можно изменить, указав его в собственном persistence.xml.
Запросы, модифицирующие данные (update, delete) приводят к сбросу (flush) в базу данных текущего персистентного контекста перед выполнением. Другими словами, ORM сначала
синхронизирует состояние сущностей в персистентном контексте и в БД, а уже потом выполняет модифицирующий запрос. Рекомендуется
выполнять такие запросы в неизмененном персистентном контексте, чтобы исключить неявные действия ORM, которые могут отрицательно
сказаться на производительности.

