如何在 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&lt;NetworkSimple&gt; 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

使用Spring Data JPA的Spring Boot

在 spring data jpa 存储库中搜索许多可选参数

带有额外列的 Spring Data JPA 多对多