如何在 Spring Data JPA 中使用带分页的投影接口?

How to use projection interfaces with pagination in Spring Data JPA?

我正在尝试使用 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 class 如下:

public interface NetworkSimple {
    Long getId();

    String getNetworkName();

    Boolean getIsActive();
}

问题可能出在方法名上。 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);

注意: 此功能应该按照原始发帖人描述的方式工作,但由于 this bug 它没有。该错误已针对 Hopper SR2 版本修复,如果您停留在早期版本上,则以下解决方法将起作用。

可以将 Pageable 与 Spring Data JPA 1.10 (Hopper) 中引入的新查询投影功能一起使用。您将需要使用 @Query 注释并手动为您需要的字段编写查询,它们还必须使用 AS 别名以允许 Spring 数据确定如何投影结果. spring 引导存储库的 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数据会自动为分页信息导出计数查询。也可以在查询中使用连接来获取关联,然后在投影中汇总它们。

我认为您需要创建 findAllProjectedBy() 作为 specification.Then 您可以使用这样的 findAll() 方法。

示例:findAll(findAllProjectedBy(),pageable)

关注 link 可能有助于找到如何在 spring 中创建规范。

https://spring.io/blog/2011/04/26/advanced-spring-data-jpa-specifications-and-querydsl/

您可以使用:

@Query("SELECT n FROM Network n")
Page<? extends NetworkSimple> findAllProjectedBy(Pageable pageable);

即使使用 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 clashes 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);
}

您可以像这样将界面投影与 Pageable 一起使用:

Page<NetworkSimple> findPagedProjectedBy(Pageable pageable);

带有一些参数:

Page<NetworkSimple> findPagedProjectedByName(String name, Pageable pageable);