Java Spring Data PageImpl 没有返回大小正确的页面?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/26720768/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Spring Data PageImpl not returning page with the correct size?
提问by dubonzi
I am trying to create a new Page
using a list of objects retrieved from the database. First I get all the elements from the DB, convert it to a Stream and then use lambda to filter the results. Then I need a Page with a set number of elements, however, instantiating a new PageImpl
doesn't seem to return a page with the correct size.
我正在尝试Page
使用从数据库中检索到的对象列表来创建一个新对象。首先,我从数据库中获取所有元素,将其转换为 Stream,然后使用 lambda 过滤结果。然后我需要一个具有一定数量元素的页面,但是,实例化一个新PageImpl
页面似乎不会返回一个具有正确大小的页面。
Here is my code:
这是我的代码:
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);
Here's a screenshot from debugging:
这是调试的屏幕截图:
Note the size in the Pageable object is set to 20 and it understands that it needs 4 pages to render the 70 elements, but it returns the whole list.
请注意,Pageable 对象中的大小设置为 20,它知道需要 4 页来呈现 70 个元素,但它返回整个列表。
What am I missing?
我错过了什么?
Edit answering the comment made by Thomas:
编辑回答托马斯的评论:
I understand how to use Page to return just a slice of the data. The code I showed was my attempt to use a lambda expression to filter my collection. The problem for me is I want to use Java 8's lambda to query the database via Spring Data JPA. Im used to VB.NET's and Entity function(x)
query expressions and was wondering how to do the same with Spring JPA.
我了解如何使用 Page 仅返回数据的一部分。我展示的代码是我尝试使用 lambda 表达式来过滤我的集合。我的问题是我想使用 Java 8 的 lambda 通过 Spring Data JPA 查询数据库。我习惯于 VB.NET 和实体function(x)
查询表达式,并且想知道如何使用 Spring JPA 做同样的事情。
In my repository, Im using extends JpaRepository<Produtos, Integer>, QueryDslPredicateExecutor<Produtos>
which gives me access to findAll(Predicate,Pageable)
. However, the Predicate is not typed so I cant simply use p -> p.getProdNome().contains("uio")
in the query. I'm using SQL Server and Hibernate.
在我的存储库中,我使用extends JpaRepository<Produtos, Integer>, QueryDslPredicateExecutor<Produtos>
它让我可以访问findAll(Predicate,Pageable)
. 但是,谓词没有键入,所以我不能简单地p -> p.getProdNome().contains("uio")
在查询中使用。我正在使用 SQL Server 和 Hibernate。
采纳答案by dubonzi
After learning more about how Spring Data works I ended up using @Query
annotations on my methods inside the JpaRepository implementations to properly query the DB and filter the results, eliminating the need to use a stream and then convert back to Page.
在详细了解 Spring Data 的工作原理后,我最终@Query
在 JpaRepository 实现中的方法上使用了注释来正确查询数据库并过滤结果,从而无需使用流然后转换回页面。
Here's how the code above would look in case anyone needs an example:
如果有人需要示例,则上面的代码如下所示:
@Query("select p from Produtos p where p.prodNome = ?1")
public Page<Produtos> productsListByName(String prodNome, Pageable pageable)
Im aware of Spring's findBy
methods but sometimes the method names become really difficult to read depending on the amount of parameters so I just stuck to JPQL.
我知道 Spring 的findBy
方法,但有时根据参数的数量,方法名称变得非常难以阅读,所以我只是坚持使用 JPQL。
Doing it this way the Page's content will always have up to the maximum amount of elements defined by you in the Spring configuration.
通过这种方式,页面的内容将始终具有您在 Spring 配置中定义的最大元素数量。
I also use a custom implementation of PageImpl
, I'm not at work right now and don't have access to the code, but I'll post it whenever I can.
我还使用了 的自定义实现PageImpl
,我现在不在工作,也无法访问代码,但我会尽可能发布它。
Edit: Custom implementation can be found here
编辑:自定义实现可以在这里找到
回答by Thomas Darimont
If I understood your code right, then your intent is to load all records from the database and and split them into x buckets that are collected in the PageImpl
, right?
如果我理解你的代码是正确的,那么你的意图是从数据库中加载所有记录并将它们拆分成 x 存储在PageImpl
.
Thats not how it used to work. The actual intent of the Pageable
and Page
abstraction is NOT
having to query all the data but just the "slice" of data that is needed.
那不是它以前的工作方式。Pageable
和Page
抽象的实际意图不是必须查询所有数据,而只是查询所需的数据“切片”。
In your case you could query the data via Page<X> page = repository.findAll(pageable);
and simply return that.
Page holds the records for the current page alongside some additional information like e.g., the total number of records and whether there is a next page.
在您的情况下,您可以通过查询数据Page<X> page = repository.findAll(pageable);
并简单地返回该数据。页面保存当前页面的记录以及一些附加信息,例如记录总数和是否有下一页。
In your client code you can use that information to render a list of records and generating next / prev links appropriately.
Note that a query with Page<X>
as result type issues 2 queries (1 to determine the overall total count for the query and 1 for the actual page data).
在您的客户端代码中,您可以使用该信息来呈现记录列表并适当地生成下一个/上一个链接。请注意,Page<X>
结果类型为 as的查询发出 2 个查询(1 个用于确定查询的总计数,1 个用于确定实际页面数据)。
If you don't need the information about the total number of results but still want to be able to generate a next link you should
use Slice<X>
as a return type - since it only issues 1 query.
如果您不需要有关结果总数的信息但仍希望能够生成下一个链接,则应将其Slice<X>
用作返回类型 - 因为它只发出 1 个查询。
回答by stites
PageImpl
is not intended to perform any kind of pagination of your list. From the docsyou can see that it's just the "basic Page
implementation" which almost sounds like what you want, but it's really misleading.
PageImpl
不打算对您的列表进行任何类型的分页。从文档中您可以看到它只是“基本Page
实现”,听起来几乎就像您想要的那样,但它确实具有误导性。
Use PagedListHolder
which is a simple state holder for handling lists of objects, separating them into pages.
使用PagedListHolder
它是一个简单的状态持有者,用于处理对象列表,将它们分成页面。
回答by Willi Mentzel
To extend stites' answer, a PagedListHolderis the way to go and here is how:
为了扩展网站的答案,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
If you need sorting, use another PagedListHolder constructorwith a MutableSortDefinition.
如果您需要排序,请使用另一个带有MutableSortDefinition 的PagedListHolder 构造函数。
回答by hatem htira
after applying a lot of methodes , this was the solution in my case and it's working
在应用了很多方法之后,这就是我的情况的解决方案并且它正在工作
> 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)
回答by AshwinK
I know it's too late to add answer. But I was also facing the same issue & I found the way for it. SimpleJpaRepository
has the method
我知道现在添加答案为时已晚。但我也面临着同样的问题,我找到了解决办法。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);
}
which is used to return Page<T>
in case you are extending JpaRepository
. So we can use the same functionality here (need to rewrite the code, as Spring doesn't give you public method to have full pagination support).
用于Page<T>
在您扩展JpaRepository
. 所以我们可以在这里使用相同的功能(需要重写代码,因为 Spring 没有给你公共方法来获得完整的分页支持)。
If you look at the method PageImpl<>(List<T> content, Pageable pageable, long total);
it just set's the value whatever you give in pageable
. Here you are sending content
as full list, but spring doesn't do it for it's internal purpose. Need to replace Page<Produtos> imp = new PageImpl<>(listaFinal,pageable,total);
with following code block.
如果您查看该方法,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));
Method getCountForQuery:
方法 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;
}
You can find the usage of PageableExecutionUtils.getPage
in
你可以找到PageableExecutionUtils.getPage
in的用法
readPage(TypedQuery<S> query, final Class<S> domainClass, Pageable pageable,
final Specification<S> spec)
method in SimpleJpaRepository
which is mostly used by findAll
internal method.
其中的方法多SimpleJpaRepository
用于findAll
内部方法。