Pagination in Spring Data JPA (limit and offset)

匿名 (未验证) 提交于 2019-12-03 02:05:01

问题:

I want the user to be able to specify the limit (the size of the amount returned) and offset (the first record returned / index returned) in my query method.

Here are my classes without any paging capabilities. My entity:

@Entity public Employee {     @Id     @GeneratedValue(strategy=GenerationType.AUTO)     private int id;      @Column(name="NAME")     private String name;      //getters and setters } 

My repository:

public interface EmployeeRepository extends JpaRepository {      @Query("SELECT e FROM Employee e WHERE e.name LIKE :name ORDER BY e.id")     public List findByName(@Param("name") String name); } 

My service interface:

public interface EmployeeService {      public List findByName(String name); } 

My service implementation:

public class EmployeeServiceImpl {      @Resource     EmployeeRepository repository;      @Override     public List findByName(String name) {         return repository.findByName(name);     } } 

Now here is my attempt at providing paging capabilities that support offset and limit. My entity class remains the same.

My "new" repository takes in a pageable parameter:

public interface EmployeeRepository extends JpaRepository {      @Query("SELECT e FROM Employee e WHERE e.name LIKE :name ORDER BY e.id")     public List findByName(@Param("name") String name, Pageable pageable); } 

My "new" service interface takes in two additional parameters:

public interface EmployeeService {      public List findByName(String name, int offset, int limit); } 

My "new" service implementation:

public class EmployeeServiceImpl {      @Resource     EmployeeRepository repository;      @Override     public List findByName(String name, int offset, int limit) {         return repository.findByName(name, new PageRequest(offset, limit);     } } 

This however isn't what i want. PageRequest specifies the page and size (page # and the size of the page). Now specifying the size is exactly what I want, however, I don't want to specify the starting page #, I want the user to be able to specify the starting record / index. I want something similar to

public List findByName(String name, int offset, int limit) {     TypedQuery query = entityManager.createQuery("SELECT e FROM Employee e WHERE e.name LIKE :name ORDER BY e.id", Employee.class);     query.setFirstResult(offset);     query.setMaxResults(limit);     return query.getResultList(); } 

Specifically the setFirstResult() and setMaxResult() methods. But I can't use this method because I want to use the Employee repository interface. (Or is it actually better to define queries through the entityManager?) Anyways, is there a way to specify the offset without using the entityManager? Thanks in advance!

回答1:

You probably can't to this with spring data jpa. If the offset is very small, you might just remove the top X statements from the query after retrieval.

Otherwise, you could define the page size to be the offset and start at page+1.



回答2:

Below code should do it. I am using in my own project and tested for most cases.

usage:

   Pageable pageable = new OffsetBasedPageRequest(offset, limit);    return this.dataServices.findAllInclusive(pageable); 

and the source code:

import org.apache.commons.lang3.builder.EqualsBuilder; import org.apache.commons.lang3.builder.HashCodeBuilder; import org.apache.commons.lang3.builder.ToStringBuilder; import org.springframework.data.domain.AbstractPageRequest; import org.springframework.data.domain.Pageable; import org.springframework.data.domain.Sort;  import java.io.Serializable;  /** * Created by Ergin **/ public class OffsetBasedPageRequest implements Pageable, Serializable {      private static final long serialVersionUID = -25822477129613575L;      private int limit;     private int offset;     private final Sort sort;      /**      * Creates a new {@link OffsetBasedPageRequest} with sort parameters applied.      *      * @param offset zero-based offset.      * @param limit  the size of the elements to be returned.      * @param sort   can be {@literal null}.      */     public OffsetBasedPageRequest(int offset, int limit, Sort sort) {         if (offset  limit;     }      @Override     public boolean equals(Object o) {         if (this == o) return true;          if (!(o instanceof OffsetBasedPageRequest)) return false;          OffsetBasedPageRequest that = (OffsetBasedPageRequest) o;          return new EqualsBuilder()                 .append(limit, that.limit)                 .append(offset, that.offset)                 .append(sort, that.sort)                 .isEquals();     }      @Override     public int hashCode() {         return new HashCodeBuilder(17, 37)                 .append(limit)                 .append(offset)                 .append(sort)                 .toHashCode();     }      @Override     public String toString() {         return new ToStringBuilder(this)                 .append("limit", limit)                 .append("offset", offset)                 .append("sort", sort)                 .toString();     } } 


回答3:

You can do that by creating your own Pageable.

Try out this basic sample. Works fine for me:

public class ChunkRequest implements Pageable {  private int limit = 0; private int offset = 0;  public ChunkRequest(int skip, int offset) {     if (skip 


回答4:

Maybe the answer is kind of late, but I thought about the same thing. Compute the current page based on offset and limit. Well, it is not exactly the same because it "assumes" that the offset is a multiple of the limit, but maybe your application is suitable for this.

@Override public List findByName(String name, int offset, int limit) {     // limit != 0 ;)     int page = offset / limit;     return repository.findByName(name, new PageRequest(page, limit); } 

I would suggest a change of the architecture. Change your controller or whatever calls the service to initially give you page and limit if possible.



回答5:

Here you go:

public interface EmployeeRepository extends JpaRepository {      @Query(value="SELECT e FROM Employee e WHERE e.name LIKE ?1 ORDER BY e.id offset ?2 limit ?3", nativeQuery = true")     public List findByNameAndMore(String name, int offset, int limit); } 


易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!