복붙노트

[SPRING] Spring 데이터 PageImpl이 올바른 크기의 페이지를 반환하지 않습니까?

SPRING

Spring 데이터 PageImpl이 올바른 크기의 페이지를 반환하지 않습니까?

데이터베이스에서 검색된 개체 목록을 사용하여 새 페이지를 만들려고합니다. 먼저 DB에서 모든 요소를 ​​가져 와서 스트림으로 변환 한 다음 람다를 사용하여 결과를 필터링합니다. 그렇다면 일련의 요소가있는 Page가 필요합니다. 그러나 새로운 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으로 설정되어 있으며 70 개의 요소를 렌더링하는 데 4 페이지가 필요하다는 것을 알고 있지만 전체 목록을 반환합니다.

내가 뭘 놓치고 있니?

Thomas가 한 의견에 답하면서 편집하십시오.

페이지를 사용하여 데이터 조각 만 반환하는 방법을 알고 있습니다. 내가 보여준 코드는 람다 식을 사용하여 내 컬렉션을 필터링하려는 시도였습니다. 저에게 문제는 Java 8의 lambda를 사용하여 Spring Data JPA를 통해 데이터베이스를 쿼리하려고한다는 것입니다. VB.NET 및 Entity 함수 (x) 쿼리 표현식에 익숙했으며 Spring JPA와 동일한 작업을 수행하는 방법에 대해 궁금해하고있었습니다.

내 리포 지 토리에서, 나는 findAll (Predicate, Pageable)에 접근 할 수있는 JpaRepository , QueryDslPredicateExecutor 를 사용했다. 그러나 술어는 입력되지 않으므로 단순히 p -> p.getProdNome (). contains ( "uio")를 쿼리에 사용하지 않습니다. SQL Server와 최대 절전 모드를 사용하고 있습니다.

해결법

  1. ==============================

    1.Spring Data의 작동 방식에 대해 더 알고 나면 JpaRepository 구현 내 메서드에서 @Query 주석을 사용하여 DB를 적절하게 쿼리하고 결과를 필터링하여 스트림을 사용할 필요가없고 페이지로 다시 변환 할 필요가 없어졌습니다.

    Spring Data의 작동 방식에 대해 더 알고 나면 JpaRepository 구현 내 메서드에서 @Query 주석을 사용하여 DB를 적절하게 쿼리하고 결과를 필터링하여 스트림을 사용할 필요가없고 페이지로 다시 변환 할 필요가 없어졌습니다.

    위의 코드는 예제가 필요한 경우를 위해 다음과 같이 표시됩니다.

    @Query("select p from Produtos p where p.prodNome = ?1")
    public Page<Produtos> productsListByName(String prodNome, Pageable pageable)
    

    나는 Spring의 findBy 메소드를 알고 있지만 때때로 매개 변수의 양에 따라 메소드 이름을 읽는 것이 어려워 져서 방금 JPQL을 고수했다.

    이런 식으로 페이지의 내용은 Spring 구성에서 사용자가 정의한 최대 요소까지 항상 유지됩니다.

    또한 PageImpl의 사용자 정의 구현을 사용합니다. 지금은 작동하지 않고 코드에 액세스 할 수 없지만 가능한 한 게시합니다.

    편집 : 사용자 정의 구현은 여기에서 찾을 수 있습니다.

  2. ==============================

    2.답을 늘리려면 PagedListHolder를 사용하는 것이 좋습니다.

    답을 늘리려면 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
    

    소트 할 필요가있는 경우, MutableSortDefinition를 사용해, 다른 PagedListHolder 생성자을 사용합니다.

  3. ==============================

    3.귀하의 코드를 올바르게 이해했다면 데이터베이스의 모든 레코드를로드하여 PageImpl에 수집 된 x 버킷으로 분할하는 것이 좋습니다.

    귀하의 코드를 올바르게 이해했다면 데이터베이스의 모든 레코드를로드하여 PageImpl에 수집 된 x 버킷으로 분할하는 것이 좋습니다.

    그게 어떻게 작동하는 데 사용되지 않습니다. 페이지 가능 및 페이지 추상화의 실제 의도는 모든 데이터를 쿼리해야하지만 필요한 데이터의 "조각"만 쿼리하면됩니다.

    귀하의 경우에는 Page page = repository.findAll (페이지 가능); 단순히 그것을 반환합니다. 페이지는 예를 들어, 총 레코드 수 및 다음 페이지의 존재 여부와 같은 몇 가지 추가 정보와 함께 현재 페이지의 레코드를 보유합니다.

    클라이언트 코드에서이 정보를 사용하여 레코드 목록을 렌더링하고 다음 / 이전 링크를 적절하게 생성 할 수 있습니다. 결과 유형으로 Page 가있는 쿼리는 2 개의 쿼리를 발행합니다 (1은 쿼리의 총 총 개수를 결정하고 1은 실제 페이지 데이터를 결정합니다).

    총 결과 수에 대한 정보가 필요하지 않지만 다음 링크를 생성 할 수 있기를 원한다면 슬라이스 를 반환 유형으로 사용합니다. 이는 하나의 쿼리 만 발행하기 때문입니다.

  4. ==============================

    4.PageImpl은 목록의 페이지 매김을 수행하지 않습니다. 문서에서 당신이 원하는 것처럼 들리는 것은 "기본 페이지 구현"일 뿐이지 만 실제로는 잘못된 것입니다.

    PageImpl은 목록의 페이지 매김을 수행하지 않습니다. 문서에서 당신이 원하는 것처럼 들리는 것은 "기본 페이지 구현"일 뿐이지 만 실제로는 잘못된 것입니다.

    PagedListHolder를 사용하십시오. PagedListHolder는 객체 목록을 처리하는 간단한 상태 홀더로서 페이지로 분리합니다.

  5. ==============================

    5.많은 메소드를 적용한 후, 이것이 제 경우의 해결책이었습니다.

    많은 메소드를 적용한 후, 이것이 제 경우의 해결책이었습니다.

    >         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)
    
  6. ==============================

    6.나는 대답을 추가하기에는 너무 늦었다는 것을 안다. 그러나 나는 또한 같은 문제에 직면했고 & 나는 그것을위한 길을 발견했다. SimpleJpaRepository에는 메소드가 있습니다.

    나는 대답을 추가하기에는 너무 늦었다는 것을 안다. 그러나 나는 또한 같은 문제에 직면했고 & 나는 그것을위한 길을 발견했다. 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);
        }
    

    JpaRepository를 확장 할 경우에 Page 를 반환하는 데 사용됩니다. 따라서 우리는 여기에서 동일한 기능을 사용할 수 있습니다 (코드를 다시 작성해야합니다. Spring은 전체 페이지 매기기 지원을 공개 메소드로 제공하지 않습니다).

    PageImpl <> (List content, Pageable pageable, long total) 메서드를 보면; 그것은 단지 당신이 페이지 가능으로주는 값입니다. 여기에서는 전체 목록으로 콘텐츠를 보내고 있지만 봄은 내부 목적으로 사용하지 않습니다. 페이지를 대체해야 함 imp = 새 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) 
    

    findAll 내부 메소드에 의해 주로 사용되는 SimpleJpaRepository의 메소드

  7. from https://stackoverflow.com/questions/26720768/spring-data-pageimpl-not-returning-page-with-the-correct-size by cc-by-sa and MIT license