setMaxResults for Spring-Data-JPA annotation?

smallufo picture smallufo · Feb 16, 2012 · Viewed 172.2k times · Source

I am trying to incorporate Spring-Data-JPA into my project. One thing that confuses me is how do I achieve setMaxResults(n) by annotation ?

for example, my code:

public interface UserRepository extends CrudRepository<User , Long>
{
  @Query(value="From User u where u.otherObj = ?1 ")
  public User findByOtherObj(OtherObj otherObj);
}

I only need to return one (and only one) User from otherObj, but I cannot find a way to annotate the maxResults. Can somebody give me a hint ?

(mysql complains :

com.mysql.jdbc.JDBC4PreparedStatement@5add5415: select user0_.id as id100_, user0_.created as created100_ from User user0_ where user0_.id=2 limit ** NOT SPECIFIED **
WARN  util.JDBCExceptionReporter - SQL Error: 0, SQLState: 07001
ERROR util.JDBCExceptionReporter - No value specified for parameter 2

)

I found a link : https://jira.springsource.org/browse/DATAJPA-147, I tried but failed. It seems not possible now? Why is such an important feature not built into Spring-Data?

If I implement this feature manually:

public class UserRepositoryImpl implements UserRepository

I have to implement tons of predefined methods in CrudRepository, this would be terrible.

environments : spring-3.1 , spring-data-jpa-1.0.3.RELEASE.jar , spring-data-commons-core-1.1.0.RELEASE.jar

Answer

Oliver Drotbohm picture Oliver Drotbohm · Feb 16, 2012

As of Spring Data JPA 1.7.0 (Evans release train).

You can use the newly introduced Top and First keywords that allow you to define query methods like this:

findTop10ByLastnameOrderByFirstnameAsc(String lastname);

Spring Data will automatically limit the results to the number you defined (defaulting to 1 if omitted). Note that the ordering of the results becomes relevant here (either through an OrderBy clause as seen in the example or by handing a Sort parameter into the method). Read more on that in the blog post covering new features of the Spring Data Evans release train or in the documentation.

For previous versions

To retrieve only slices of data, Spring Data uses the pagination abstraction which comes with a Pageable interface on the requesting side as well as a Page abstraction on the result side of things. So you could start with

public interface UserRepository extends Repository<User, Long> {

  List<User> findByUsername(String username, Pageable pageable);
}

and use it like this:

Pageable topTen = new PageRequest(0, 10);
List<User> result = repository.findByUsername("Matthews", topTen);

If you need to know the context of the result (which page is it actually? is it the first one? how many are there in total?), use Page as return type:

public interface UserRepository extends Repository<User, Long> {

  Page<User> findByUsername(String username, Pageable pageable);
}

The client code can then do something like this:

Pageable topTen = new PageRequest(0, 10);
Page<User> result = repository.findByUsername("Matthews", topTen);
Assert.assertThat(result.isFirstPage(), is(true));

Not that we will trigger a count projection of the actual query to be executed in case you use Page as return type as we need to find out how many elements there are in total to calculate the metadata. Beyond that, be sure you actually equip the PageRequest with sorting information to get stable results. Otherwise you might trigger the query twice and get different results even without the data having changed underneath.