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, если это возможно.