Spring Данные - почему невозможно выполнить подкачку с помощью собственного запроса
Скажем, у нас есть объект с именем MyEntity
. Можно запросить результаты с помощью страницы @Query
и с именованными запросами, например
@Query(value = "select e from MyEntity e where e.enabled = true")
Page<MyEntity> findAllEnabled(Pageable pageable);
Тем не менее, невозможно выполнить то же самое с собственным запросом, поэтому это
@Query(value = "select * from my_entity where enabled = true", nativeQuery = true)
Page<MyEntity> findAllEnabled(Pageable pageable);
не будет работать.
В чем причины этого? Возможно ли сделать Pageable работающим с собственными запросами?
Ответы
Ответ 1
Это описание, приведенное в документации данных jpa (http://docs.spring.io/spring-data/jpa/docs/1.8.0.M1/reference/html/)
Собственные запросы Аннотации @Query позволяют выполнять собственные запросы установив флаг nativeQuery в значение true. Обратите внимание, что мы в настоящее время не поддержка выполнения разбивки на страницы или динамической сортировки для собственных запросов поскольку wed должен манипулировать фактическим запросом, объявленным, и мы не можем сделать это надежно для собственного SQL.
JPQL реферат SQL-реализации и его спецификаций провайдеров, а также ответственность за структуру ORM для создания правильного SQL.
-
Итак, используя Pagination в форме JPQL, spring просто нужно создать правильный JPQL, и он будет интерпретироваться на уровне ORM для исправления SQL.
-
При выполнении этого с SQL подразумевается, что spring знает, как сгенерировать правильный SQL для огромного большинства СУБД, дублируя функциональность ORM, что слишком много накладных расходов.
Ответ 2
Я не знаю, действительно ли это относится к вам: по крайней мере, в Spring Data JPA 1.9.4 вы можете указать два запроса.
Для репозитория:
interface FoobarEntityRepository extends JpaRepository<FoobarEntity, Integer> {
Page findFoobarsSpecialQuery(String someParameter, final Pageable pageable);
}
Вы можете добавить 2 собственных запроса к своей сущности, одну для самого запроса и одну для оператора count:
@Entity
@SqlResultSetMappings({
@SqlResultSetMapping(name = "SqlResultSetMapping.count", columns = @ColumnResult(name = "cnt"))
})
@NamedNativeQueries({
@NamedNativeQuery(
name = "FoobarEntity.findFoobarsSpecialQuery",
resultClass = DailyPictureEntity.class,
query = "Select * from foobars f where someValue = :someParameter "
),
@NamedNativeQuery(
name = "FoobarEntity.findFoobarsSpecialQuery.count",
resultSetMapping = "SqlResultSetMapping.count",
query = "Select count(*) as cnt from foobars f where someValue = :someParameter "
)
})
FoobarEntity {
}
Трюк заключается в том, чтобы указать запрос на подсчет с суффиксом .count
. Это также работает с аннотацией Spring Data @Query
.
Обратите внимание, что вам требуется сопоставление наборов результатов SQL для запроса count.
Это действительно очень приятно.
Ответ 3
Существует способ использования Pageable с собственными запросами с возможностью использования Spel данных Spring, здесь упоминается здесь.
Вы можете найти пример в этом репозитории.
/**
* @see DATAJPA-564
*/
@Query(
value = "select * from (select rownum() as RN, u.* from SD_User u) where RN between ?#{ #pageable.offset -1} and ?#{#pageable.offset + #pageable.pageSize}",
countQuery = "select count(u.id) from SD_User u", nativeQuery = true)
Page<User> findUsersInNativeQueryWithPagination(Pageable pageable);
Функция сортировки не будет работать должным образом, если есть подзапрос в предложении from
или ваш собственный запрос, и вы хотите применить к нему динамический вид. Способ, которым это можно сделать, - переместить подзапрос в предложение where
.
Spring данные будут добавлены к концу вашего запроса " order by "
, если в Pageable
есть объект Sort
. (с данными Spring 1.10.3)
Лучше всего преобразовать собственный запрос в jpql, если это возможно.