Разбиение на страницы в весенних данных JPA (limit и offset)
Я хочу, чтобы пользователь мог указать предел (размер возвращаемой суммы) и смещение (первая возвращаемая запись / возвращаемый индекс) в моем методе запроса.
вот мои классы без возможности подкачки. Мое существо:
@Entity
public Employee {
@Id
@GeneratedValue(strategy=GenerationType.AUTO)
private int id;
@Column(name="NAME")
private String name;
//getters and setters
}
мой репозиторий:
public interface EmployeeRepository extends JpaRepository<Employee, Integer> {
@Query("SELECT e FROM Employee e WHERE e.name LIKE :name ORDER BY e.id")
public List<Employee> findByName(@Param("name") String name);
}
мои услуги-интерфейс:
public interface EmployeeService {
public List<Employee> findByName(String name);
}
моя реализация сервиса:
public class EmployeeServiceImpl {
@Resource
EmployeeRepository repository;
@Override
public List<Employee> findByName(String name) {
return repository.findByName(name);
}
}
теперь вот моя попытка предоставить возможности подкачки, которые поддерживают смещение и ограничение. Мой класс сущности остается прежним.
мой" новый " репозиторий принимает параметр подкачки:
public interface EmployeeRepository extends JpaRepository<Employee, Integer> {
@Query("SELECT e FROM Employee e WHERE e.name LIKE :name ORDER BY e.id")
public List<Employee> findByName(@Param("name") String name, Pageable pageable);
}
мой" новый " интерфейс службы принимает два дополнительных параметра:
public interface EmployeeService {
public List<Employee> findByName(String name, int offset, int limit);
}
моя" новая " реализация сервиса:
public class EmployeeServiceImpl {
@Resource
EmployeeRepository repository;
@Override
public List<Employee> findByName(String name, int offset, int limit) {
return repository.findByName(name, new PageRequest(offset, limit);
}
}
это, однако, не то, что я хочу. PageRequest указывает страницу и размер (page # и размер страницы). Теперь указание размера-это именно то, что я хочу, однако я не хочу указывать начальная страница #, я хочу, чтобы пользователь мог указать начальную запись / индекс. Я хочу что-то похожее на
public List<Employee> findByName(String name, int offset, int limit) {
TypedQuery<Employee> 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();
}
в частности, методы setFirstResult() и setMaxResult (). Но я не могу использовать этот метод, потому что хочу использовать интерфейс репозитория сотрудников. (Или на самом деле лучше определить запросы через entityManager?) В любом случае, есть ли способ указать смещение без использования entityManager? Заранее спасибо!
5 ответов
ниже код должен делать это. Я использую в своем собственном проекте и протестирован для большинства случаев.
использование:
Pageable pageable = new OffsetBasedPageRequest(offset, limit);
return this.dataServices.findAllInclusive(pageable);
и исходный код:
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 < 0) {
throw new IllegalArgumentException("Offset index must not be less than zero!");
}
if (limit < 1) {
throw new IllegalArgumentException("Limit must not be less than one!");
}
this.limit = limit;
this.offset = offset;
this.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 direction the direction of the {@link Sort} to be specified, can be {@literal null}.
* @param properties the properties to sort by, must not be {@literal null} or empty.
*/
public OffsetBasedPageRequest(int offset, int limit, Sort.Direction direction, String... properties) {
this(offset, limit, new Sort(direction, properties));
}
/**
* Creates a new {@link OffsetBasedPageRequest} with sort parameters applied.
*
* @param offset zero-based offset.
* @param limit the size of the elements to be returned.
*/
public OffsetBasedPageRequest(int offset, int limit) {
this(offset, limit, new Sort(Sort.Direction.ASC,"id"));
}
@Override
public int getPageNumber() {
return offset / limit;
}
@Override
public int getPageSize() {
return limit;
}
@Override
public int getOffset() {
return offset;
}
@Override
public Sort getSort() {
return sort;
}
@Override
public Pageable next() {
return new OffsetBasedPageRequest(getOffset() + getPageSize(), getPageSize(), getSort());
}
public OffsetBasedPageRequest previous() {
return hasPrevious() ? new OffsetBasedPageRequest(getOffset() - getPageSize(), getPageSize(), getSort()) : this;
}
@Override
public Pageable previousOrFirst() {
return hasPrevious() ? previous() : first();
}
@Override
public Pageable first() {
return new OffsetBasedPageRequest(0, getPageSize(), getSort());
}
@Override
public boolean hasPrevious() {
return 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();
}
}
вы можете сделать это, создав свой собственный Pageable.
попробуйте этот базовый образец. Отлично работает для меня:
public class ChunkRequest implements Pageable {
private int limit = 0;
private int offset = 0;
public ChunkRequest(int skip, int offset) {
if (skip < 0)
throw new IllegalArgumentException("Skip must not be less than zero!");
if (offset < 0)
throw new IllegalArgumentException("Offset must not be less than zero!");
this.limit = offset;
this.offset = skip;
}
@Override
public int getPageNumber() {
return 0;
}
@Override
public int getPageSize() {
return limit;
}
@Override
public int getOffset() {
return offset;
}
@Override
public Sort getSort() {
return null;
}
@Override
public Pageable next() {
return null;
}
@Override
public Pageable previousOrFirst() {
return this;
}
@Override
public Pageable first() {
return this;
}
@Override
public boolean hasPrevious() {
return false;
}
}
вы, вероятно, не можете это сделать с spring data jpa. Если смещение очень мало, вы можете просто удалить верхние операторы X из запроса после извлечения.
в противном случае, вы можете определить размер страницы, смещение в странице+1.
возможно, ответ немного запоздал, но я думал о том же самом. Вычислите текущую страницу на основе offset и limit. Ну, это не совсем то же самое, потому что он "предполагает", что смещение кратно предела, но, возможно, ваше приложение подходит для этого.
@Override
public List<Employee> findByName(String name, int offset, int limit) {
// limit != 0 ;)
int page = offset / limit;
return repository.findByName(name, new PageRequest(page, limit);
}
Я бы предложил изменить архитектуру. Измените контроллер или все, что вызывает службу, чтобы изначально дать вам страницу и ограничить, если это возможно.
здесь вы идете:
public interface EmployeeRepository extends JpaRepository<Employee, Integer> {
@Query(value="SELECT e FROM Employee e WHERE e.name LIKE ?1 ORDER BY e.id offset ?2 limit ?3", nativeQuery = true")
public List<Employee> findByNameAndMore(String name, int offset, int limit);
}