Spring-Data-JPA 注释的 setMaxResults?

问题描述 投票:0回答:10

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

例如我的代码:

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

我只需要从 otherObj 返回

one (and only one)
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

java spring jpa spring-data spring-data-jpa
10个回答
211
投票

自 Spring Data JPA 1.7.0(Evans 发布系列)开始。

您可以使用新引入的

Top
First
关键字,它们允许您定义如下查询方法:

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
配备了排序信息以获得稳定的结果。否则,即使下面的数据没有更改,您也可能会触发查询两次并得到不同的结果。


120
投票

如果您使用 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));
  }

}

31
投票

有一种方法可以提供与“通过注释的 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)

28
投票

使用 Spring Data Evans(1.7.0 发布)

新发布的 Spring Data JPA 以及另一个名为 Evans 的模块列表具有使用关键字

Top20
First
来限制查询结果的功能,

这样你现在就可以写了

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

List<User> findTop20ByLastnameOrderByIdDesc(String lastname);

或单个结果

List<User> findFirstByLastnameOrderByIdDesc(String lastname);

15
投票

对我来说最好的选择是原生查询:

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

11
投票

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());

6
投票

也可以使用@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();

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>


0
投票

12年后我不敢相信。 Sping-Data-JPA仍然没有实际的解决方案。 我最终编写了一个自定义存储库实现。

public class CustomJpaRepository <Entity, Id> extends JpaRepositoryImplementation<Entity, Id> {
  Optional<Entity> findFirst(String query, Map<String, Object> parameters, String entityGraph);
}

public class CustomExtendedJpaRepository<E, I> extends SimpleJpaRepository<E, I> implements ExtendedJpaRepository<E, I>{

    private final EntityManager entityManager;
    private final Class<E> domainClass;

    public CustomExtendedJpaRepository(JpaEntityInformation<E, I> entityInformation, EntityManager em) {
        super(entityInformation, em);
        this.entityManager = em;
        this.domainClass = entityInformation.getJavaType();
    }

    public CustomExtendedJpaRepository(Class<E> domainClass, EntityManager em) {
        super(domainClass, em);
        this.entityManager = em;
        this.domainClass = domainClass;
    }
    
    @Override
    public Optional<E> findFirst(String query, Map<String, Object> parameters, String entityGraph) {
        var tq = entityManager.createQuery(query, domainClass);
        for (var p : parameters.entrySet()) {
            tq.setParameter(p.getKey(), p.getValue());
        }
        if (entityGraph != null) {
            tq.setHint(AvailableHints.HINT_SPEC_FETCH_GRAPH, entityManager.getEntityGraph(entityGraph));
        }
        tq.setMaxResults(1);
        return Optional.ofNullable(tq.getSingleResult());
    }
}

启用自定义实现

@EnableJpaRepositories(
        basePackages = "your.company.persistence",
        repositoryBaseClass = CustomExtendedJpaRepository.class
)

-1
投票

使用

Pageable pageable = PageRequest.of(0,1);
Page<Transaction> transactionsPage = transactionRepository.findAll(specification, pageable);
return transactionsPage.getContent();
© www.soinside.com 2019 - 2024. All rights reserved.