Luca
Luca

Reputation: 351

Spring data r2dbc and pagination

I'm using the new spring data r2dbc module and i'm able to extract the data using a ReactiveCrudRepository. Now i need to introduce pagination but i cannot manage to do it. I tried with this

public interface TestRepository extends ReactiveCrudRepository<MyEntity, Long> {
    Flux<MyEntity> findByEntityId(Long entityId, Pageable page);
}

but when i try to execute this i obtain this error

org.springframework.data.repository.query.ParameterOutOfBoundsException: Invalid parameter index! You seem to have declared too little query method parameters!
    at org.springframework.data.repository.query.Parameters.getParameter(Parameters.java:237)
    Suppressed: reactor.core.publisher.FluxOnAssembly$OnAssemblyException: 

is there a way to use pagination with this module?

Upvotes: 13

Views: 17320

Answers (4)

K. Siva Prasad Reddy
K. Siva Prasad Reddy

Reputation: 12405

The newer versions of Spring Data R2dbc accepts Pageable as @Hantsy mentioned, but there is a catch.

If you are fetching all the records without any WHERE clause then following is NOT working:

public interface MyEntityRepository extends ReactiveCrudRepository<MyEntity, Long> {
    Flux<MyEntity> findAll(Pageable pageable);
}

Changing findAll() to findBy() is working fine.

public interface MyEntityRepository extends ReactiveCrudRepository<MyEntity, Long> {
    Flux<MyEntity> findBy(Pageable pageable);
}

Upvotes: 3

David Keating
David Keating

Reputation: 13

I was able to achieve this using spring-boot-starter-data-r2dbc.2.4.3

As @Hantsy said the ReactiveCrudRepository will accept Pageable as a parameter inside of the queries but this won't solve the paging issue. In hibernate you expect to be returned a Page of an Object but for Reactive it's going to be a Flux.

I was however able to achieve this by using the PageImpl class and using the count method from the ReactiveCrudRepository interface.

For example

public interface TestRepository extends ReactiveCrudRepository<MyEntity, Long> {
    Flux<MyEntity> findByEntityId(Long entityId, Pageable page);
}
public Mono<<Page<MyEntity>> getMyEntities(Long entityId, PageRequest request) {
    return testRepository.findByEntityId(entityId, request)
            .collectList()
            .zipWith(testRepository.count())
            .flatMap(entityTuples -> 
                new PageImpl<>(entityTuples.getT1(), request, entityTuples.getT2()));
}

Upvotes: 0

Hantsy
Hantsy

Reputation: 9359

The new R2dbcEntityTemplate Spring Data R2dbc 1.2 contains pagination operations like this.

 private final R2dbcEntityTemplate template;

    public Flux<Post> findByTitleContains(String name) {
        return this.template.select(Post.class)
                .matching(Query.query(where("title").like("%" + name + "%")).limit(10).offset(0))
                .all();
    }

Spring Data R2dbc 1.2 (not released yet) will accept a Pageable parameter as in Repository.

 public Flux<PostSummary> findByTitleLike(String title, Pageable pageable);

The complete code examples, check here, test codes.

Upvotes: 13

NikolaB
NikolaB

Reputation: 4956

No, there currently is no way to use implicit pagination. You should specify your whole queries to use it.

Here is an example:

@Query("SELECT * FROM my_entity WHERE entity_id = :entityId OFFSET :offset LIMIT :limit")
Flux<MyEntity> findByEntityId(Long entityId, int offset, int limit);

Upvotes: 6

Related Questions