Spring JPA 具有可分页和子查询导致查询语法错误

use*_*364 4 hibernate spring-data spring-data-jpa

我有一个 Spring 数据存储库,定义如下:

public interface InvoiceRepository extends JpaRepository<Invoice, Long> {
   @Query(value = "select i.id as id,  " +
            "i.invoiceStatus as invoiceStatus, " +
            "(select sum(r.id) from Invoice r ) as paid " +
            "from Invoice i ")
    Page<InvoiceQuery> getInvoicesByStatusAndName(Pageable pageable);

}
Run Code Online (Sandbox Code Playgroud)

上面给出的子查询不是真正的子查询,但这个简单的查询有助于重现问题。

当我的 springboot(2.4.5) 应用程序启动时,出现以下异常

引起原因:java.lang.IllegalArgumentException:org.hibernate.hql.internal.ast.QuerySyntaxException:期待 EOF,在第 1 行第 62 列附近找到 ')' [从 com.anish.webacc.orm.entities 选择 count(r) .Invoice r ) 从 com.anish.webacc.orm.entities.Invoice i ] 支付,位于 org.hibernate.internal.ExceptionConverterImpl.convert(ExceptionConverterImpl.java:138) ~[hibernate-core-5.4.30.Final.jar :5.4.30.最终]

现在如果我改变

Page<InvoiceQuery> getInvoicesByStatusAndName(Pageable pageable);
Run Code Online (Sandbox Code Playgroud)

List<InvoiceQuery> getInvoicesByStatusAndName(Pageable pageable);
Run Code Online (Sandbox Code Playgroud)

然后它就可以完美工作(没有分页部分)。

InvoiceQuery 是一个投影接口 -

public interface InvoiceQuery {
    Long getId();
    InvoiceStatus getInvoiceStatus();
    Double getPaid();
}
Run Code Online (Sandbox Code Playgroud)

看来生成的查询不正确 - 由于某种原因,我怀疑子查询中的括号导致了问题。如果我删除子查询,我就没有问题

这是我第一次尝试进行分页,所以我可能在这里做了一些非常愚蠢的事情 - 任何帮助将不胜感激。

谢谢-阿尼什

Luc*_*cia 5

问题是当您使用内部查询时 Spring data JPA 无法派生计数查询。当您希望返回类型为 Page 时,请参阅 Page - 将总页数和总元素数作为与分页结果一起返回的两个内容。

   int getTotalPages();

    long getTotalElements();
Run Code Online (Sandbox Code Playgroud)

因此,要获取这两个东西,即符合您的条件的总元素和给定页面大小的总页数,它必须派生一个 count() 查询,在您的情况下,它无法派生该 count() 查询。您可以在“@Query”注释中显式指定计数查询。像下面这样

  @Query(value = "select new com.example.package.InvoiceQuery(i.id as id,i.invoiceStatus as invoiceStatus,(select sum(r.id) from Invoice r ) as paid ) from Invoice i",
 countQuery = "select count(*) from Invoice")
    Page<InvoiceQuery> getInvoicesByStatusAndName(Pageable pageable);
Run Code Online (Sandbox Code Playgroud)