如何在 Spring Data JPA 中使用带有分页的投影接口?
Posted
技术标签:
【中文标题】如何在 Spring Data JPA 中使用带有分页的投影接口?【英文标题】:How to use projection interfaces with pagination in Spring Data JPA? 【发布时间】:2016-08-10 15:02:14 【问题描述】:我正在尝试使用spring数据的新功能projections获取部分实体(NetworkSimple)的页面
我已经检查了文档,如果我只要求:
Collection<NetworkSimple> findAllProjectedBy();
它可以工作,但如果我使用的是可分页的:
Page<NetworkSimple> findAllProjectedBy(Pageable pageable);
它会抛出一个错误:
org.hibernate.jpa.criteria.expression.function.AggregationFunction$COUNT cannot be cast to org.hibernate.jpa.criteria.expression.CompoundSelectionImpl
有人已经用过这个了吗?
我的 NetworkSimple 类如下:
public interface NetworkSimple
Long getId();
String getNetworkName();
Boolean getIsActive();
【问题讨论】:
【参考方案1】:问题可能来自方法名称。 by 关键字表示您通过特定属性过滤数据:例如 findByName。它称为从方法名称创建查询:
http://docs.spring.io/spring-data/jpa/docs/1.10.1.RELEASE/reference/html/#repositories.query-methods.query-creation
所以试试Page<NetworkSimple> findAll(Pageable pageable);
【讨论】:
如果我删除“By”,它会返回一条错误消息,因为它无法创建查询。org.springframework.data.mapping.PropertyReferenceException: No property findAllProjected found for type Network!
我的错,你应该使用 findAll 方法名
但我不能使用它,因为返回的是一个网络对象,我想要投影。
看来你可以在你的仓库中添加注解来指定投影:github.com/spring-projects/spring-data-examples/blob/master/…【参考方案2】:
注意:此功能应该按照原始海报描述的方式工作,但由于this bug 它没有。该错误已针对 Hopper SR2 版本进行了修复,如果您卡在较早的版本上,则以下解决方法将起作用。
可以将Pageable
与 Spring Data JPA 1.10 (Hopper) 中引入的新查询投影功能一起使用。您将需要使用 @Query
注释并手动为您需要的字段编写查询,它们还必须使用 AS
进行别名,以允许 Spring Data 弄清楚如何投影结果。在 Spring Boot 存储库的 spring-boot-samples 部分中有一个很好的示例。
在你的例子中它会很简单:
@Query("SELECT n.id AS id, n.name AS networkName, n.active AS isActive FROM Network n")
Page<NetworkSimple> findAllProjectedBy(Pageable pageable);
我假设您的实体看起来像这样:
@Entity
public class Network
@Id
@GeneratedValue
private Long id;
@Column
private String name;
@Column
private boolean active;
...
Spring Data 将自动为分页信息派生一个计数查询。也可以使用查询中的连接来获取关联,然后在投影中汇总它们。
【讨论】:
这并不完全正确。这实际上应该像原始海报所期望的那样工作,但您提供了一个有效的解决方法。我已经更改了原始发布者提交的the ticket,以使用您的解决方法更新文档以修复实际错误。如果您可以更新答案以提及它,那就太酷了。修复将在 Hopper SR2 中。 票证已修复,快照构建可用,将包含在 Hopper 的 SR2 中。 @OliverGierke 我已经更新了答案。我原以为这只是一个限制,因为我找不到任何以这种方式使用它的例子。【参考方案3】:我认为你需要创建findAllProjectedBy()
作为规范。然后你可以使用findAll()
这样的方法。
示例:findAll(findAllProjectedBy(),pageable)
以下链接可能有助于了解如何在 spring 中创建规范。
https://spring.io/blog/2011/04/26/advanced-spring-data-jpa-specifications-and-querydsl/
【讨论】:
【参考方案4】:你可以使用:
@Query("SELECT n FROM Network n")
Page<? extends NetworkSimple> findAllProjectedBy(Pageable pageable);
【讨论】:
【参考方案5】:即使使用 spring-data-jpa 1.11.4,类似
public interface NetworkRepository extends JpaRepository<Network, String>
Page<NetworkSimple> findAll(Pageable pageable);
不会编译;举报
findAll(org.springframework.data.domain.Pageable) in NetworkRepository ***es with findAll(org.springframework.data.domain.Pageable) in org.springframework.data.repository.PagingAndSortingRepository
return type org.springframework.data.domain.Page<NetworkSimple> is not compatible with org.springframework.data.domain.Page<Network>
我们找到的解决方法是将 findAll 重命名为 findAllBy,例如
public interface NetworkRepository extends JpaRepository<Network, String>
Page<NetworkSimple> findAllBy(Pageable pageable);
【讨论】:
【参考方案6】:您可以像这样将界面投影与 Pageable 一起使用:
Page<NetworkSimple> findPagedProjectedBy(Pageable pageable);
带有一些参数:
Page<NetworkSimple> findPagedProjectedByName(String name, Pageable pageable);
【讨论】:
以上是关于如何在 Spring Data JPA 中使用带有分页的投影接口?的主要内容,如果未能解决你的问题,请参考以下文章
如何使用带有 Pageable 的 Spring Data JPA 分页来更改数据?
如何在不使用查询缓存的情况下缓存 Spring Data JPA 查询方法的结果?
如何使用 QueryDSL 在 Spring Data JPA 中使用 order by 和 Limit