MySQL 5.6データベースで最新のspring-data(1.10.2)を使用するWebプロジェクトで、ページネーションでネイティブクエリを使用しようとしていますが、起動時にorg.springframework.data.jpa.repository.query.InvalidJpaQueryMethodException
が発生しています。
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
パラメーターが含まれているため、hasPagingOrSortingParameter
はtrue
ですが、queryString
内の#pageable
または#sort
シーケンスも探していますが、これは提供していません。
私はクエリの最後に#pageable
(コメントです)を追加しようとしましたが、これは検証に合格しますが、実行時にクエリが2つのパラメータではなく3つの追加パラメータを期待していると言って失敗します.
おかしいのは、実行中に手動でcontainsPageableOrSortInQueryExpression
をfalse
からtrue
に変更すると、クエリが正常に機能するため、その文字列がqueryString
にあることを確認している理由がわからず、提供する方法がわからないことです。
どんな助けでも大歓迎です。
Update 01/30/2018spring-dataプロジェクトの開発者は PR by Jens Schauder でこの問題の修正に取り組んでいるようです
事前にお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」コメントの周りの改行は、予想されるパラメーターの数の実行時エラーを回避するために必要です(回避策回避策)。このバグがすぐに修正されることを願っています...
このコードは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
用です。 countQuery
はPage<>
用です。
記録のために、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)。
@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);
これを試して:
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
)
私は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);
}
次の両方のアプローチは、ネイティブクエリのページ付けに関してMySQLで正常に機能します。ただし、H2では機能しません。 sql構文エラーが表示されます。
/ #pageable /を?#{#pageable}に置き換えると、ページネーションが可能になります。 PageableDefaultを追加すると、ページ要素のサイズを設定できます。
以下のように機能します:
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);
}
「ORDER BY id\n#pageable\n」の代わりに「ORDER BY id DESC\n-- #pageable\n」を使用すると、MS SQL SERVERで機能しました。