3.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
установлено представление, то по умолчанию Query
имеет FlushModeType.AUTO
, что влияет на случай, когда в текущем персистентном контексте содержатся измененные экземпляры сущностей: эти экземпляры будут сохранены в БД перед выполнением запроса. Другими словами, ORM сначала синхронизирует состояние сущностей в персистентном контексте и в БД, а уже потом выполняет запрос. Этим гарантируется, что в результаты запроса попадут все соответствующие экземпляры, даже если они еще не были сохранены в базе данных явно. Обратной стороной этого является неявный flush, т.е. выполнение команд SQL update для всех измененных в данном контексте сущностей, что может повлиять на производительность.
Если же Query
выполняется без представления, то по умолчанию Query
имеет FlushModeType.COMMIT
, что означает, что неявный flush вызван не будет, и запрос не будет учитывать содержимое текущего персистентного контекста.
В большинстве случаев игнорирование текущего персистентного контекста допустимо, и является предпочтительным поведением, так как не вызывает дополнительных команд SQL. Однако, при использовании представлений существует следующая проблема: если в персистентном контексте есть измененный экземпляр сущности, и выполняется запрос с представлением и FlushModeType.COMMIT
, загружающий этот же экземпляр, то изменения будут потеряны. Поэтому по умолчанию мы используем FlushModeType.AUTO
для запросов с представлением.
Вы также можете явно установить flush mode с помощью метода setFlushMode()
интерфейса Query
, чтобы переопределить режим по умолчанию.