Spring Data PageImpl没有返回正确大小的页面?

时间:2014-11-03 18:38:09

标签: java spring spring-mvc spring-data spring-data-jpa

我正在尝试使用从数据库中检索的对象列表创建新的Page。首先,我从DB获取所有元素,将其转换为Stream,然后使用lambda过滤结果。然后我需要一个具有一定数量元素的页面,但是,实例化一个新的PageImpl似乎不会返回一个具有正确大小的页面。

这是我的代码:

List<Produtos> listaFinal;
Stream<Produtos> stream = produtosRepository.findAll().stream();
listaFinal = stream.filter(p -> p.getProdNome().contains("uio")).collect(Collectors.toList());

long total = listaFinal.size();
Page<Produtos> imp = new PageImpl<>(listaFinal,pageable,total);

以下是调试的截图:

请注意,Pageable对象的大小设置为20,并且它理解它需要4个页面来呈现70个元素,但它返回整个列表。

我错过了什么?

编辑回答托马斯的评论:

我理解如何使用Page返回一小部分数据。我展示的代码是我尝试使用lambda表达式来过滤我的集合。对我来说问题是我想使用Java 8的lambda通过Spring Data JPA查询数据库。我习惯了VB.NET和实体function(x)查询表达式,并想知道如何对Spring JPA做同样的事情。

在我的存储库中,我使用extends JpaRepository<Produtos, Integer>, QueryDslPredicateExecutor<Produtos>来访问findAll(Predicate,Pageable)。但是,谓词没有输入,所以我不能在查询中使用p -> p.getProdNome().contains("uio")。我正在使用SQL Server和Hibernate。

6 个答案:

答案 0 :(得分:6)

要延长stites' answer,我需要PagedListHolder,方法如下:

List<String> list = // ...

// Creation
PagedListHolder page = new PagedListHolder(list);
page.setPageSize(10); // number of items per page
page.setPage(0);      // set to first page

// Retrieval
page.getPageCount(); // number of pages 
page.getPageList();  // a List which represents the current page

如果您需要排序,请使用另一个PagedListHolder constructorMutableSortDefinition

答案 1 :(得分:4)

在了解了有关Spring Data如何工作的更多信息后,我最终在JpaRepository实现中的方法上使用 @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { if (requestCode == PICK_FILE_REQUEST) { if(data!=null){ Logv("Data","got some data"); } } } 注释来正确查询数据库并过滤结果,从而无需使用流然后转换回页。

如果有人需要一个例子,上面的代码将如何显示:

@Query

我知道Spring的@Query("select p from Produtos p where p.prodNome = ?1") public Page<Produtos> productsListByName(String prodNome, Pageable pageable) 方法,但有时方法名称变得非常难以阅读,这取决于参数的数量,所以我只是坚持使用JPQL。

这样做,Page的内容将始终具有Spring配置中定义的最大元素数量。

我还使用findBy的自定义实现,我现在不在工作,无法访问代码,但我会随时发布。

修改:可以找到自定义实施here

答案 2 :(得分:3)

如果我理解你的代码是正确的,那么你的意图是从数据库中加载所有记录,并将它们分成在PageImpl中收集的x桶,对吗?

这不是以前的工作方式。 PageablePage抽象的实际意图不是 必须查询所有数据,但只需查询&#34;切片&#34;需要的数据。

在您的情况下,您可以通过Page<X> page = repository.findAll(pageable);查询数据,然后返回。 页面包含当前页面的记录以及一些其他信息,例如记录总数以及是否有下一页。

在您的客户端代码中,您可以使用该信息呈现记录列表并适当地生成下一个/上一个链接。 请注意,Page<X>作为结果类型的查询会发出2个查询(1表示查询的总计数,1表示实际页面数据)。

如果您不需要有关结果总数的信息,但仍希望能够生成下一个链接,那么您应该 使用Slice<X>作为返回类型 - 因为它只发出1个查询。

答案 3 :(得分:3)

PageImpl无意对您的列表执行任何类型的分页。 From the docs你可以看到它只是“基本Page实现”,几乎听起来像你想要的,但它确实具有误导性。

使用PagedListHolder这是一个简单的状态持有者,用于处理对象列表,将它们分成页面。

答案 4 :(得分:0)

在应用了很多方法之后,这就是我的解决方案,并且可以正常工作

>         int pageSize = pageable.getPageSize();
>         long pageOffset = pageable.getOffset();
>         long total = pageOffset + list.size() + (list.size() == pageSize ? pageSize : 0);
>         Page<listType> page = new PageImpl<listType>(list, pageable,total)

答案 5 :(得分:0)

我知道添加答案为时已晚。但是我也面临着同样的问题,并且找到了解决之道。 SimpleJpaRepository具有方法

public Page<T> findAll(Specification<T> spec, Pageable pageable) {

        TypedQuery<T> query = getQuery(spec, pageable);
        return pageable == null ? new PageImpl<T>(query.getResultList())
                : readPage(query, getDomainClass(), pageable, spec);
    }

,用于扩展Page<T>时用于返回JpaRepository。因此,我们可以在此处使用相同的功能(需要重写代码,因为Spring不会为您提供公共方法以提供完整的分页支持)。

如果您查看方法PageImpl<>(List<T> content, Pageable pageable, long total);,则只需设置您在pageable中提供的值即可。在这里,您将发送content作为完整列表,但是spring并不是出于内部目的。需要用以下代码块替换Page<Produtos> imp = new PageImpl<>(listaFinal,pageable,total);

TypedQuery<User> query = entityManager.createQuery(criteriaQuery); // Users type can be replaced with Produtos or any other db entity.

query.setFirstResult(pageable.getOffset());
query.setMaxResults(pageable.getPageSize());

List<User> users= query.getResultList();
Page<User> result=PageableExecutionUtils.getPage(users,pageable, () -> getCountForQuery(User.class));

方法getCountForQuery:

private Long getCountForQuery(Class<?> t){

    CriteriaBuilder criteriaBuilder=entityManager.getCriteriaBuilder();

    CriteriaQuery<Long> countQuery = criteriaBuilder
            .createQuery(Long.class);
    countQuery.select(criteriaBuilder.count(
            countQuery.from(t)));
    Long count = entityManager.createQuery(countQuery)
            .getSingleResult();

    return count;
}

您可以在

中找到PageableExecutionUtils.getPage的用法
readPage(TypedQuery<S> query, final Class<S> domainClass, Pageable pageable,
            final Specification<S> spec) 

SimpleJpaRepository中的方法,该方法主要由findAll内部方法使用。