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