web-dev-qa-db-ja.com

ページネーションを使用したSpringデータとネイティブクエリ

MySQL 5.6データベースで最新のspring-data(1.10.2)を使用するWebプロジェクトで、ページネーションでネイティブクエリを使用しようとしていますが、起動時にorg.springframework.data.jpa.repository.query.InvalidJpaQueryMethodExceptionが発生しています。

UPDATE:20180306この問題は Spring 2.0.4 で修正されました。回避策の関連する回答とコメント。

spring-dataドキュメントの@Queryの使用の例5 によると、次のようにクエリ自体とcountQueryを指定することが可能です。

public interface UserRepository extends JpaRepository<User, Long> {
  @Query(value = "SELECT * FROM USERS WHERE LASTNAME = ?1",
    countQuery = "SELECT count(*) FROM USERS WHERE LASTNAME = ?1",
    nativeQuery = true)
  Page<User> findByLastname(String lastname, Pageable pageable);
}

好奇心から、NativeJpaQueryクラスでは、有効なjpaクエリであるかどうかを確認する次のコードが含まれていることがわかります。

public NativeJpaQuery(JpaQueryMethod method, EntityManager em, String queryString, EvaluationContextProvider evaluationContextProvider, SpelExpressionParser parser) {
   super(method, em, queryString, evaluationContextProvider, parser);
   JpaParameters parameters = method.getParameters();
   boolean hasPagingOrSortingParameter = parameters.hasPageableParameter() || parameters.hasSortParameter();
   boolean containsPageableOrSortInQueryExpression = queryString.contains("#pageable") || queryString.contains("#sort");
   if(hasPagingOrSortingParameter && !containsPageableOrSortInQueryExpression) {
       throw new InvalidJpaQueryMethodException("Cannot use native queries with dynamic sorting and/or pagination in method " + method);
   }
}

クエリにはPageableパラメーターが含まれているため、hasPagingOrSortingParametertrueですが、queryString内の#pageableまたは#sortシーケンスも探していますが、これは提供していません。

私はクエリの最後に#pageable(コメントです)を追加しようとしましたが、これは検証に合格しますが、実行時にクエリが2つのパラメータではなく3つの追加パラメータを期待していると言って失敗します.

おかしいのは、実行中に手動でcontainsPageableOrSortInQueryExpressionfalseからtrueに変更すると、クエリが正常に機能するため、その文字列がqueryStringにあることを確認している理由がわからず、提供する方法がわからないことです。

どんな助けでも大歓迎です。

Update 01/30/2018spring-dataプロジェクトの開発者は PR by Jens Schauder でこの問題の修正に取り組んでいるようです

46
Lasneyx

事前におaび申し上げます。これは、元の質問と Janar からのコメントをほぼまとめたものですが...

私は同じ問題に遭遇します: Spring Dataの例5 がページネーション付きのネイティブクエリを持つ必要性のソリューションとして見つかりましたが、Springは起動時にネイティブクエリでページネーションを使用できないと文句を言いました。

次のコードを使用して、ページネーションを使用して、必要なネイティブクエリを正常に実行できたことを報告したかっただけです。

    @Query(value="SELECT a.* "
            + "FROM author a left outer join mappable_natural_person p on a.id = p.provenance_id "
            + "WHERE p.update_time is null OR (p.provenance_name='biblio_db' and a.update_time>p.update_time)"
            + "ORDER BY a.id \n#pageable\n", 
        /*countQuery="SELECT count(a.*) "
            + "FROM author a left outer join mappable_natural_person p on a.id = p.provenance_id "
            + "WHERE p.update_time is null OR (p.provenance_name='biblio_db' and a.update_time>p.update_time) \n#pageable\n",*/
        nativeQuery=true)
public List<Author> findAuthorsUpdatedAndNew(Pageable pageable);

クエリの戻り値の型としてPage<Author>を使用するにはcountQuery(コードブロックでコメント化されています)が必要です。「#pageable」コメントの周りの改行は、予想されるパラメーターの数の実行時エラーを回避するために必要です(回避策回避策)。このバグがすぐに修正されることを願っています...

33
Emanuele Fusco

このコードはPostgreSQLとMySQLで動作します:

public interface UserRepository extends JpaRepository<User, Long> {
  @Query(value = "SELECT * FROM USERS WHERE LASTNAME = ?1 ORDER BY ?#{#pageable}",
    countQuery = "SELECT count(*) FROM USERS WHERE LASTNAME = ?1",
    nativeQuery = true)
  Page<User> findByLastname(String lastname, Pageable pageable);
}

ORDER BY ?#{#pageable}Pageable用です。 countQueryPage<>用です。

20
Dmitry Stolbov

記録のために、H2をテストデータベースとして使用し、MySQLを実行時に使用すると、このアプローチは機能します(例は グループ内の最新のオブジェクト ):

@Query(value = "SELECT t.* FROM t LEFT JOIN t AS t_newer " +
        "ON t.object_id = t_newer.object_id AND t.id < t_newer.id AND o_newer.user_id IN (:user_ids) " +
        "WHERE t_newer.id IS NULL AND t.user_id IN (:user_ids) " +
        "ORDER BY t.id DESC \n-- #pageable\n",
        countQuery = "SELECT COUNT(1) FROM t WHERE t.user_id IN (:user_ids) GROUP BY t.object_id, t.user_id",
        nativeQuery = true)
Page<T> findByUserIdInGroupByObjectId(@Param("user_ids") Set<Integer> userIds, Pageable pageable);

Spring Data JPA 1.10.5、H2 1.4.194、MySQL Community Server 5.7.11-log(innodb_version 5.7.11)。

10
maricn

@Lasneyxのようなまったく同じ症状があります。 Postgresネイティブクエリの回避策

@Query(value = "select * from users where user_type in (:userTypes) and user_context='abc'--#pageable\n", nativeQuery = true)
List<User> getUsersByTypes(@Param("userTypes") List<String> userTypes, Pageable pageable);
6
689

これを試して:

public interface UserRepository extends JpaRepository<User, Long> {
  @Query(value = "SELECT * FROM USERS WHERE LASTNAME = ?1 ORDER BY /*#pageable*/",
    countQuery = "SELECT count(*) FROM USERS WHERE LASTNAME = ?1",
    nativeQuery = true)
  Page<User> findByLastname(String lastname, Pageable pageable);
}

"/* */"の場合はOracle notation

5
XmasPiano

私はOracleデータベースを使用しましたが、結果は得られませんでしたが、d-manが上で述べたコンマが生成されたエラーが出ました。

それから私の解決策は:

Pageable pageable = new PageRequest(current, rowCount);

Pagableを作成するときまでに順序なしで見ることができるように。

そして、DAOのメソッド:

public interface UserRepository extends JpaRepository<User, Long> {
  @Query(value = "SELECT * FROM USERS WHERE LASTNAME = ?1 /*#pageable*/ ORDER BY LASTNAME",
    countQuery = "SELECT count(*) FROM USERS WHERE LASTNAME = ?1",
    nativeQuery = true)
  Page<User> findByLastname(String lastname, Pageable pageable);
 }
4
Level_Up

次の両方のアプローチは、ネイティブクエリのページ付けに関してMySQLで正常に機能します。ただし、H2では機能しません。 sql構文エラーが表示されます。

  • ORDER BY?#{#pageable}
  • ORDER BY a.id\n#pageable\n
1
wmao

/ #pageable /を?#{#pageable}に置き換えると、ページネーションが可能になります。 PageableDefaultを追加すると、ページ要素のサイズを設定できます。

0
Mohit Thakkar

以下のように機能します:

public interface UserRepository extends JpaRepository<User, Long> {
    @Query(value = "select * from (select (@rowid\\:=@rowid+1) as RN, u.* from USERS u, (SELECT @rowid\\:=0) as init where  LASTNAME = ?1) as total"+
        "where RN between ?#{#pageable.offset-1} and ?#{#pageable.offset + #pageable.pageSize}",
    countQuery = "SELECT count(*) FROM USERS WHERE LASTNAME = ?1",
    nativeQuery = true)
    Page<User> findByLastname(String lastname, Pageable pageable);
}
0
Fonda Wu

「ORDER BY id\n#pageable\n」の代わりに「ORDER BY id DESC\n-- #pageable\n」を使用すると、MS SQL SERVERで機能しました。

0
Muhamed Saudi