setMaxResults用于Spring-Data-JPA注释?


127

我正在尝试将Spring-Data-JPA合并到我的项目中。使我困惑的一件事是如何通过注释实现setMaxResults(n)?

例如,我的代码:

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

我只需one (and only one)要从otherObj 返回User,但找不到任何方法来注释maxResults。有人可以给我一个提示吗?

(mysql抱怨:

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

我找到了一个链接:https : //jira.springsource.org/browse/DATAJPA-147,我尝试但失败了。现在看来不可能了吗?为什么这么重要的功能没有内置在Spring-Data中?

如果我手动实现此功能:

public class UserRepositoryImpl implements UserRepository

我必须在中实现大量的预定义方法CrudRepository,这将是可怕的。

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

Answers:


175

从Spring Data JPA 1.7.0开始(Evans发布培训)。

您可以使用新引入的TopFirst关键字来定义查询方法,如下所示:

findTop10ByLastnameOrderByFirstnameAsc(String lastname);

Spring Data将自动将结果限制为您定义的数字(如果省略,则默认为1)。请注意,结果的排序在这里变得相关(通过OrderBy示例中的子句或将Sort参数传递给方法)。在涵盖Spring Data Evans发行培训的新功能的博客文章中或在文档中了解更多内容

对于以前的版本

为了只检索数据片段,Spring Data使用了分页抽象,该分页抽象Pageable在请求方带有一个接口,在Page事物的结果侧也带有一个抽象。所以你可以开始

public interface UserRepository extends Repository<User, Long> {

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

并像这样使用它:

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

如果您需要知道结果的上下文(实际上是哪一页?它是第一页吗?总共有几页?),请Page用作返回类型:

public interface UserRepository extends Repository<User, Long> {

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

然后,客户端代码可以执行以下操作:

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

如果您将其Page用作返回类型,我们并不是会触发要执行的实际查询的计数预测,因为我们需要找出总共有多少个元素来计算元数据。除此之外,请确保您确实为配备了PageRequest排序信息,以获得稳定的结果。否则,即使下面的数据没有更改,您也可能触发两次查询并获得不同的结果。


14
谢谢,但是我仍然希望有一个“基于注释”的解决方案。因为在这种情况下,“页面/可分页”功能过于强大。客户必须创建一个Pageable / Page来检索“一个且只有一个”结果...使用起来非常不友好。看来您负责Spring-Data,希望您可以进一步调查这个问题:stackoverflow.com/questions/9276461/…。您可以确认是否是Spring-Data的错误吗?
smallufo 2012年

1
+
可行

1
这里触发了一个计数查询,如果我们想要一个有限的查询,这是完全没有必要的。
azerafati 2014年

1
如果您将其List用作方法的返回类型,则不是。
奥利弗·德罗博姆

3
我想,TopFirst关键字并不适用于使用方法@Query的注释?只有那些使用基于方法名称的查询生成?
Ruslan Stelmachenko

106

如果您使用的是Java 8和Spring Data 1.7.0,那么如果要将@Query注释与设置最大结果结合使用,则可以使用默认方法:

public interface UserRepository extends PagingAndSortingRepository<User,Long> {
  @Query("from User u where ...")
  List<User> findAllUsersWhereFoo(@Param("foo") Foo foo, Pageable pageable);

  default List<User> findTop10UsersWhereFoo(Foo foo) {
    return findAllUsersWhereFoo(foo, new PageRequest(0,10));
  }

}

3
可能对单个结果有用Stream<User> ... {...} default Optional<User> ... { ...findAny() }
xenoterracide

28

您可以通过以下方式提供等效的“通过注释提供setMaxResults(n)”:

public interface ISomething extends JpaRepository<XYZ, Long>
{
    @Query("FROM XYZ a WHERE a.eventDateTime < :before ORDER BY a.eventDateTime DESC")
    List<XYZ> findXYZRecords(@Param("before") Date before, Pageable pageable);
}

当将一个可分页的页面作为参数发送时,这应该可以解决问题。例如,要获取前10条记录,您需要将可分页设置为此值:

new PageRequest(0, 10)

如果您使用的是Pagable,则其返回Page <XYZ>而不是List <XYZ>
Arundev

@Arundev错误- List正常工作(并且避免了前面的评论中count已经提到的不必要的查询)
Janaka Bandara

21

使用Spring Data Evans(1.7.0 RELEASE)

Spring Data JPA的新版本与另一个称为Evans的模块列表一起,具有使用关键字Top20First限制查询结果的功能,

所以你现在可以写

List<User> findTop20ByLastname(String lastname, Sort sort);

要么

List<User> findTop20ByLastnameOrderByIdDesc(String lastname);

或单项结果

List<User> findFirstByLastnameOrderByIdDesc(String lastname);

5
可选的<User> findFirstByLastnameOrderByIdDesc(String lastname);
krmanish007'6

在获得前20个结果之后,当我使用分页转到网站的下一页时,如何获得下20个结果?
kittu

@kittu,这当然是另一个问题,但是您需要传递一个Pageable对象。查看春季文档
azerafati

为什么他们让该方法返回该死的列表(如果指定了FIRST?)?
Vasile Surdu '18

13

对我来说最好的选择是本机查询:

@Query(value="SELECT * FROM users WHERE other_obj = ?1 LIMIT 1", nativeQuery = true)
User findByOhterObj(OtherObj otherObj);

不确定Hibernate是否支持该限制:forum.hibernate.org/viewtopic.php?f=
t

2
打破了整个概念!最好改用EntityManager!
Spektakulatius

@ Code.IT我传播了KISS概念。除了该JPA nativeQuery 注释参数外,还添加了不可忽略的参数。
Grigory Kislin '17

@GKislin比您必须重命名诸如findLimitOneByOtherObj之类的方法。另外,您还忘记添加一个OrderBy,如果other_obj不是唯一的,则会导致错误的结果。否则,在唯一列上的where语句应该足够而没有限制
-Spektakulatius

LIMIT关键字不是休眠的,而是postgres / mysql
Acewin

5

如果您的课程@Repository扩展了,JpaRepository您可以使用下面的示例。

int limited = 100;
Pageable pageable = new PageRequest(0,limited);
Page<Transaction> transactionsPage = transactionRepository.findAll(specification, pageable);
return transactionsPage.getContent();

getContent返回一个List<Transaction>


如果我在查询中有2个条件,例如transactionRepository.findByFirstNameAndLastName(firstname,lastname),该怎么办?能行吗?我收到此异常org.springframework.data.mapping.PropertyReferenceException:找不到类型为Board的属性。
Shailesh

4

使用@QueryHints也可以。下面的示例使用org.eclipse.persistence.config.QueryHints#JDBC_MAX_ROWS

@Query("SELECT u FROM User u WHERE .....")
@QueryHints(@QueryHint(name = JDBC_MAX_ROWS, value = "1"))
Voter findUser();

我已经测试了此代码,但无法正常工作。也不例外,但是没有合适的结果。此外,关于QueryHints的文档非常少。见下文。 docs.spring.io/spring-data/jpa/docs/1.7.1.RELEASE/reference/...
bogdan.rusu

IIRC,不能保证将遵循查询提示。这只是将“友好的建议”传递给实现的一种方法。
Priidu Neemre '16

@QueryHints({@QueryHint(name = org.hibernate.annotations.FETCH_SIZE, value = "1")})在Hibernate中尝试过,但是别名:(不起作用
Grigory Kislin

2
org.hibernate.annotations.FETCH_SIZE它的提取大小,没有限制,不是最大结果。Hiber不能播放
Zhuravskiy Vitaliy

4

new PageRequest(0,10)在较新的Spring版本中不起作用(我正在使用2.2.1.RELEASE)。基本上,构造函数有一个附加参数作为Sort类型。此外,构造函数protected使您必须使用其子类之一或调用其of静态方法:

PageRequest.of(0, 10, Sort.sort(User.class).by(User::getFirstName).ascending()))

您还可以省略Sort参数的使用,并隐式地使用默认排序方式(按pk等方式排序):

PageRequest.of(0, 10)

您的函数声明应如下所示:

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

该函数将是:

userRepository.findByUsername("Abbas", PageRequest.of(0,10, Sort.sort(User.class).by(User::getLastName).ascending());
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.