[英]Spring Data and Native Query with pagination
In a web project, using latest spring-data (1.10.2) with a MySQL 5.6 database, I'm trying to use a native query with pagination but I'm experiencing an org.springframework.data.jpa.repository.query.InvalidJpaQueryMethodException
at startup. In a web project, using latest spring-data (1.10.2) with a MySQL 5.6 database, I'm trying to use a native query with pagination but I'm experiencing an
org.springframework.data.jpa.repository.query.InvalidJpaQueryMethodException
at启动。
According to Example 50 at Using @Query from spring-data documentation this is possible specifying the query itself and a countQuery, like this:根据来自 spring-data 文档的使用 @Query 的示例 50,可以指定查询本身和 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);
}
Out of curiosity, In NativeJpaQuery
class I can see that it contains the following code to check if it's a valid jpa query:出于好奇,在
NativeJpaQuery
class 中,我可以看到它包含以下代码来检查它是否是有效的 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);
}
}
My query contains a Pageable
parameter, so hasPagingOrSortingParameter
is true
, but it's also looking for a #pageable
or #sort
sequence inside the queryString
, which I do not provide.我的查询包含一个
Pageable
参数,因此hasPagingOrSortingParameter
是true
,但它也在queryString
中寻找#pageable
或#sort
序列,我没有提供。
I've tried adding #pageable
(it's a comment) at the end of my query, which makes validation to pass but then, it fails at execution saying that the query expects one additional parameter: 3 instead of 2.我尝试在查询末尾添加
#pageable
(它是一条注释),这使得验证通过,但随后执行失败,说查询需要一个额外的参数:3 而不是 2。
Funny thing is that, if I manually change containsPageableOrSortInQueryExpression
from false
to true
while running, the query works fine so I don't know why it's checking for that string to be at my queryString
and I don't know how to provide it.有趣的是,如果我在运行时手动将
containsPageableOrSortInQueryExpression
从false
更改为true
,则查询工作正常,所以我不知道为什么它会检查该字符串是否位于我的queryString
中,而且我不知道如何提供它。
Any help would be much appreciated.任何帮助将非常感激。
Update 01/30/2018 It seems that developers at spring-data project are working on a fix for this issue with a PR by Jens Schauder 2018 年 1 月 30 日更新似乎 spring-data 项目的开发人员正在通过 Jens Schauder 的 PR解决此问题
My apologies in advance, this is pretty much summing up the original question and the comment from Janar , however...我提前道歉,这几乎是对原始问题和Janar评论的总结,但是......
I run into the same problem: I found the Example 50 of Spring Data as the solution for my need of having a native query with pagination but Spring was complaining on startup that I could not use pagination with native queries.我遇到了同样的问题:我发现Spring Data的示例 50作为我需要使用分页的本机查询的解决方案,但 Spring 在启动时抱怨我无法对本机查询使用分页。
I just wanted to report that I managed to run successfully the native query I needed, using pagination, with the following code:我只是想报告,我使用以下代码成功运行了我需要的本机查询,使用分页:
@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);
The countQuery (that is commented out in the code block) is needed to use Page<Author>
as the return type of the query, the newlines around the "#pageable" comment are needed to avoid the runtime error on the number of expected parameters (workaround of the workaround). countQuery(在代码块中注释掉)需要使用
Page<Author>
作为查询的返回类型,“#pageable”注释周围的换行符需要避免预期参数数量的运行时错误(解决方法的解决方法)。 I hope this bug will be fixed soon...希望这个bug能早点修复。。。
This is a hack for program using Spring Data JPA before Version 2.0.4 .这是使用Spring Data JPA 版本 2.0.4 之前的程序的黑客。
Code has worked with PostgreSQL and MySQL :代码已与 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}
is for Pageable
. ORDER BY ?#{#pageable}
用于Pageable
。 countQuery
is for Page<User>
. countQuery
用于Page<User>
。
Just for the record, using H2 as testing database, and MySQL at runtime, this approach works (example is newest object in group ):只是为了记录,使用 H2 作为测试数据库,并在运行时使用 MySQL,这种方法有效(例如group 中的最新对象):
@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). Spring Data JPA 1.10.5、H2 1.4.194、MySQL Community Server 5.7.11-log (innodb_version 5.7.11)。
Try this:试试这个:
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);
}
( "/* */"
for Oracle notation
) (
"/* */"
为Oracle notation
)
I have exact same symptom like @Lasneyx.我有与@Lasneyx 完全相同的症状。 My workaround for Postgres native query
我对 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);
I use oracle database and I did not get the result but an error with generated comma which d-man speak about above.我使用 oracle 数据库,但没有得到结果,但生成的逗号错误,d-man 在上面谈到了这个错误。
Then my solution was:然后我的解决方案是:
Pageable pageable = new PageRequest(current, rowCount);
As you can see without order by when create Pagable.正如您在创建 Pagable 时无序所见。
And the method in the DAO:以及 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);
}
Both the following approaches work fine with MySQL for paginating native query.以下两种方法都适用于 MySQL 对本机查询进行分页。 They doesn't work with H2 though.
但它们不适用于 H2。 It will complain the sql syntax error.
它会抱怨 sql 语法错误。
I could successfully integrate Pagination in我可以成功地将 Pagination 集成到
spring-data-jpa-2.1.6
spring-data-jpa-2.1.6
as follows.如下。
@Query(
value = “SELECT * FROM Users”,
countQuery = “SELECT count(*) FROM Users”,
nativeQuery = true)
Page<User> findAllUsersWithPagination(Pageable pageable);
使用 "ORDER BY id DESC \\n-- #pageable\\n " 而不是 "ORDER BY id \\n#pageable\\n" 对我的 MS SQL SERVER 有用
I am adding this answer just as a placeholder for those users who are using more recent versions of Spring Boot.我添加这个答案只是作为那些使用更新版本 Spring Boot 的用户的占位符。 On Spring Boot 2.4.3, I observed that none of the workaround were necessary, and the following code worked straight out of the box for me:
在 Spring Boot 2.4.3 上,我发现不需要任何解决方法,以下代码对我来说是开箱即用的:
public interface UserRepository extends JpaRepository<User, Long> {
@Query(value="SELECT * FROM USERS WHERE LASTNAME = ?1", nativeQuery=true)
Page<User> findByLastname(String lastname, Pageable pageable);
}
The countQuery
definition was not necessary, and a call to Page#getTotalElements()
in fact already was returning the correct count, as returned by JPA's own internal count query. countQuery
定义不是必需的,实际上对Page#getTotalElements()
的调用已经返回了正确的计数,正如 JPA 自己的内部计数查询所返回的那样。
The above code is extremely powerful, offering pagination made via a native query, yet which return results into actual Java entities (rather than the ugly and bulky List<Object[]>
, which sometimes is necessary).上面的代码非常强大,提供通过本机查询进行的分页,但将结果返回到实际的 Java 实体中(而不是丑陋而笨重的
List<Object[]>
,有时这是必要的)。
public interface ProductsCustomRepository extends JpaRepository<ProductResultEntity, Long> {
@Query(
value = "select tableA.id, tableB.bank_name from tableA join tableB on tableA.id = tableB.a_id where tableA.id = :id
and (:fieldX is null or tableA.fieldX LIKE :fieldX)",
countQuery = "select count(*) from tableA join tableB on tableA.id = tableB.a_id where tableA.id = :id
and (:fieldX is null or tableA.fieldX LIKE :fieldX)",
nativeQuery = true
)
Page<ProductResultEntity> search(@Param("id") Long aId,
@Param("fieldX") String keyword, Pageable pageable
);
}
create view zzz as select * from tableA join tableB on tableA.id = tableB.a_id
productsRepository.search("123", "%BANK%", PageRequest.of(0, 5, Sort.by(Sort.Direction.ASC, "id")));
@Entity
public class ProductResultEntity {
private Long id;
private String bank;
@Id
@Column(name = "id", nullable = false)
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
@Column(name = "bank_name", nullable = false)
public String getBank() {
return bank;
}
public void setBank(String bank) {
this.bank = bank;
}
}
It does work as below:它的工作原理如下:
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);
}
For me below worked in MS SQL对我来说,下面在 MS SQL 中工作
@Query(value="SELECT * FROM ABC r where r.type in :type ORDER BY RAND() \n-- #pageable\n ",nativeQuery = true)
List<ABC> findByBinUseFAndRgtnType(@Param("type") List<Byte>type,Pageable pageable);
I'm using the code below.
我正在使用下面的代码。
working
工作
@Query(value = "select * from user usr" +
"left join apl apl on usr.user_id = apl.id" +
"left join lang on lang.role_id = usr.role_id" +
"where apl.scr_name like %:scrname% and apl.uname like %:uname and usr.role_id in :roleIds ORDER BY ?#{#pageable}",
countQuery = "select count(*) from user usr" +
"left join apl apl on usr.user_id = apl.id" +
"left join lang on lang.role_id = usr.role_id" +
"where apl.scr_name like %:scrname% and apl.uname like %:uname and usr.role_id in :roleIds",
nativeQuery = true)
Page<AplUserEntity> searchUser(@Param("scrname") String scrname,@Param("uname") String uname,@Param("roleIds") List<Long> roleIds,Pageable pageable);
Removing \\n#pageable\\n from both query and count query worked for me.从查询和计数查询中删除 \\n#pageable\\n 对我有用。 Springboot version : 2.1.5.RELEASE DB : Mysql
Springboot 版本:2.1.5.RELEASE 数据库:Mysql
This worked for me (I am using Postgres) in Groovy:这在 Groovy 中对我有用(我使用的是 Postgres):
@RestResource(path="namespaceAndNameAndRawStateContainsMostRecentVersion", rel="namespaceAndNameAndRawStateContainsMostRecentVersion")
@Query(nativeQuery=true,
countQuery="""
SELECT COUNT(1)
FROM
(
SELECT
ROW_NUMBER() OVER (
PARTITION BY name, provider_id, state
ORDER BY version DESC) version_partition,
*
FROM mydb.mytable
WHERE
(name ILIKE ('%' || :name || '%') OR (:name = '')) AND
(namespace ILIKE ('%' || :namespace || '%') OR (:namespace = '')) AND
(state = :state OR (:state = ''))
) t
WHERE version_partition = 1
""",
value="""
SELECT id, version, state, name, internal_name, namespace, provider_id, config, create_date, update_date
FROM
(
SELECT
ROW_NUMBER() OVER (
PARTITION BY name, provider_id, state
ORDER BY version DESC) version_partition,
*
FROM mydb.mytable
WHERE
(name ILIKE ('%' || :name || '%') OR (:name = '')) AND
(namespace ILIKE ('%' || :namespace || '%') OR (:namespace = '')) AND
(state = :state OR (:state = ''))
) t
WHERE version_partition = 1
/*#{#pageable}*/
""")
public Page<Entity> findByNamespaceContainsAndNameContainsAndRawStateContainsMostRecentVersion(@Param("namespace")String namespace, @Param("name")String name, @Param("state")String state, Pageable pageable)
The key here was to use: /*#{#pageable}*/
这里的关键是使用:
/*#{#pageable}*/
It allows me to do sorting and pagination.它允许我进行排序和分页。 You can test it by using something like this: http://localhost:8080/api/v1/entities/search/namespaceAndNameAndRawStateContainsMostRecentVersion?namespace=&name=&state=published&page=0&size=3&sort=name,desc
您可以使用以下内容对其进行测试: http://localhost:8080/api/v1/entities/search/namespaceAndNameAndRawStateContainsMostRecentVersion?namespace=&name=&state=published&page=0&size=3&sort=name,desc
Watch out for this issue: Spring Pageable does not translate @Column name注意这个问题: Spring Pageable 不会翻译@Column 名称
You can use below code for h2 and MySQl您可以将以下代码用于 h2 和 MySQl
@Query(value = "SELECT req.CREATED_AT createdAt, req.CREATED_BY createdBy,req.APP_ID appId,req.NOTE_ID noteId,req.MODEL model FROM SUMBITED_REQUESTS req inner join NOTE note where req.NOTE_ID=note.ID and note.CREATED_BY= :userId "
,
countQuery = "SELECT count(*) FROM SUMBITED_REQUESTS req inner join NOTE note WHERE req.NOTE_ID=note.ID and note.CREATED_BY=:userId",
nativeQuery = true)
Page<UserRequestsDataMapper> getAllRequestForCreator(@Param("userId") String userId,Pageable pageable);
You can achieve it by using following code,您可以使用以下代码实现它,
@Query(value = "SELECT * FROM users u WHERE ORDER BY ?#{#pageable}", nativeQuery = true)
List<User> getUsers(String name, Pageable pageable);
Simply use ORDER BY ?#{#pageable} and pass page request to your method.只需使用ORDER BY ?#{#pageable}并将页面请求传递给您的方法。
Enjoy!享受!
@Query(value = "select " +
//"row_number() over (order by ba.order_num asc) as id, " +
"row_number() over () as id, " +
"count(ba.order_num),sum(ba.order_qty) as sumqty, " +
"ba.order_num, " +
"md.dpp_code,md.dpp_name, " +
"from biz_arrangement ba " +
"left join mst_dpp md on ba.dpp_code = md.dpp_code " +
"where 1 = 1 " +
"AND (:#{#flilter.customerCodeListCheck}='' OR ba.customer_code IN (:#{#flilter.customerCodeList})) " +
"AND (:#{#flilter.customerNameListCheck}='' OR ba.customer_name IN (:#{#flilter.customerNameList})) " +
"group by " +
"ba.order_num, " +
"md.dpp_code,md.dpp_name ",
countQuery = "select " +
"count ( " +
"distinct ( " +
"ba.order_num, " +
"md.dpp_code,md.dpp_name) " +
")" +
"from biz_arrangement ba " +
"left join mst_dpp md on ba.dpp_code = md.dpp_code " +
"where 1 = 1 " +
"AND (:#{#flilter.customerCodeListCheck}='' OR ba.customer_code IN (:#{#flilter.customerCodeList})) " +
"AND (:#{#flilter.customerNameListCheck}='' OR ba.customer_name IN (:#{#flilter.customerNameList})) ",
nativeQuery = true)
Page<Map<String, Object>> nativeQueryDynamicPageAndSort(@Param("flilter") Flilter flilter, Pageable pageable);
no need to add?#{#pageable}, the problem I got is when I use不需要加吗?#{#pageable},我遇到的问题是我使用的时候
row_number() over (order by ba.order_num asc) as id,
the input sort won't work when I change to当我更改为时,输入排序将不起作用
row_number() over () as id,
the dynamic input sort and pagination are both okay!动态输入排序和分页都可以!
This is a group by query with a row id.这是具有行 ID 的查询分组。
Replacing / #pageable / with ?#{#pageable} allow to do pagination.用 ?#{# pageable } 替换 / #pageable / 允许进行分页。 Adding PageableDefault allow you to set size of page Elements.
添加 PageableDefault 允许您设置页面元素的大小。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.