Как разбить JPA на запрос
У меня есть таблица представления с такими столбцами, как ID
, Name
, Code
и другие свойства. Мое требование состоит в том, чтобы искать записи на основе упомянутых свойств и возвращать разбитый на страницы набор.
Это псевдокод для того, что я ищу:
searchSubmission(searchFilter sf,pageIndex,noOfRecords) {
query = 'from submisssion where code=sf.code or id=sf.id order by id start_from (pageIndex*noOfRecords) limit noOfRecords'
return result();
}
Кажется, есть много вариантов, таких как CriteriaBuilder
, NamedQuery
и т.д. Какой из них наиболее эффективен в этой ситуации?
Ответы
Ответ 1
Для всех объектов запросов JPA (кроме собственных запросов SQL) вы должны использовать разбиение на страницы через методы setMaxResults (int) и setFirstResult (int). Например:
return em.createNamedQuery("yourqueryname", YourEntity.class)
.setMaxResults(noOfRecords)
.setFirstResult(pageIndex * noOfRecords)
.getResultList();
JPA выполнит для вас нумерацию страниц.
Именованные запросы просто предопределены и могут быть кэшированы, в то время как другие типы создаются динамически.
Таким образом, выбор заключается в использовании JPQL, как:
Query query = em.createQuery("SELECT s FROM Submission s WHERE s.code = :code or s.id = :id ORDER BY s.id", Submission.class);
Или CriteriaBuilder API для формирования аналогичного запроса:
CriteriaBuilder qb = em.getCriteriaBuilder();
CriteriaQuery<Submission> cq = qb.createQuery(Submission.class);
Root<Submission> root = cq.from(Submission.class);
cq.where( qb.or(
qb.equal(root.get("code"), qb.parameter(String.class, "code")),
qb.equal(root.get("id"), qb.parameter(Integer.class, "id"))
));
Query query = em.createQuery(cq);
Не забудьте установить значения параметров, например, используя query.setParameter("id", sf.id).
Ответ 2
Вы можете использовать Pageable
в методе репозитория
@Repository
public interface StateRepository extends JpaRepository<State, Serializable> {
@Query("select state from State state where state.stateId.stateCode = ?1")
public State findStateByCode(String code, Pageable pageable);
}
И на уровне сервиса вы можете создать объект Pageable
:
@Autowire
StateRepository stateRepository;
public State findStateServiceByCode(String code, int page, int size) {
Pageable pageable = new PageRequest(page, size);
Page<Order> statePage = stateRepository.findStateByCode(code, pageable);
return statePage.getContent();
}
Ответ 3
Как я объяснил в этой статье, вы можете использовать пагинацию JPA как для запросов сущностей, так и для собственного SQL.
Чтобы ограничить размер базового запроса ResultSet
, интерфейс Query
JPA предоставляет метод setMaxResults
.
Навигация по следующей странице требует размещения набора результатов там, где закончилась последняя страница. Для этого интерфейс Query
JPA предоставляет метод setFirstResult
.
Использование нумерации страниц с запросом JPQL выглядит следующим образом:
List<Post> posts = entityManager
.createQuery(
"select p " +
"from Post p " +
"order by p.createdOn ")
.setFirstResult(10)
.setMaxResults(10)
.getResultList();
Criteria API точно такой же, так как вам нужно создать Query
из CriteriaQuery
:
CriteriaBuilder qb = em.getCriteriaBuilder();
CriteriaQuery<Post> cq = qb.createQuery(Post.class);
Root<Post> root = cq.from(Post.class);
cq.orderBy(qb.asc(root.get("createdOn")));
List<Post> posts = em
.createQuery(cq)
.setFirstResult(10)
.setMaxResults(10)
.getResultList();