如何在使用Spring Data Repository中的@Query时限制结果

44

我正在使用 Spring Data JPA 中的 CrudRepository 检索数据。我想要从我的自定义查询中检索到的记录进行过滤。我尝试使用 .setMaxResults(20); 来选择前 20 行。但是出现了错误。我想要从我的表中筛选出前 20 行。

这是我的存储库

package lk.slsi.repository;

import java.util.Date;
import lk.slsi.domain.SLSNotification;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.CrudRepository;
import org.springframework.data.repository.query.Param;

import java.util.List;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import org.hibernate.SessionFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;

/**
 * Created by ignotus on 2/10/2017.
 */
public interface SLSNotificationRepository extends CrudRepository<SLSNotification, Integer> {


    @Override
    SLSNotification save(SLSNotification slsNotification);

    @Override
    SLSNotification findOne(Integer snumber);

    @Override
    long count();

    @Override
    void delete(Integer integer);

    @Override
    void delete(SLSNotification slsNotification);

    @Override
    void delete(Iterable<? extends SLSNotification> iterable);

    @Override
    List<SLSNotification> findAll();

    @Query("select a from SLSNotification a where a.slsiUnit in :unitList order by snumber desc")
    List<SLSNotification> getApplicationsByUnit(@Param("unitList") List<String> unitList);

    @Query("select a from SLSNotification a where a.userId = :userId")
    List<SLSNotification> getApplicationsByUserId(@Param("userId") String userId);

    @Query("select a.snumber, a.date, a.slsNo, a.slsiUnit, a.productDesc, a.status from SLSNotification a where a.userId = :userId ORDER BY snumber desc")
    List<SLSNotification> getApplicationsByUserIdforManage(@Param("userId") String userId);

    @Query("select a from SLSNotification a where a.slsNo = :slsNo")
    SLSNotification getApplicationBySLSNumber(@Param("slsNo") String slsNo);

}
我希望我的List<SLSNotification> getApplicationsByUserIdforManage(@Param("userId") String userId);方法检索有限的数据集。我该如何调用实体管理器或其他任何东西来完成此操作?
请帮我做到这一点。output img

为什么你的 HQL 语句中不使用 limit 关键字呢? - Shafin Mahmud
我尝试添加限制,但在HQL中它不起作用...你确定它能工作吗? - Nipun Vidarshana
请展示一下您如何在HQL中尝试使用“limit”关键字?如果无法正常工作,会出现什么错误或异常? - Shafin Mahmud
@Query("select a.snumber, a.date, a.slsNo, a.slsiUnit, a.productDesc, a.status from SLSNotification a where a.userId = :userId ORDER BY snumber desc limit 20") - Nipun Vidarshana
当您尝试使用一些本地查询时,应该在“@Query”中加入“nativeQuery = true”。您尝试过这样做吗? - Shafin Mahmud
@Shafin Mahmud 我添加了上面的代码,但它不起作用。 - Nipun Vidarshana
5个回答

73

您可以在SQL中使用limit语句来提供限制条件,并且在@Query注释中将nativeQuery = true设置为JPA提供程序(如Hibernate)将其视为本机 SQL查询。

@Query(nativeQuery = true, value = "SELECT * FROM SLSNotification s WHERE s.userId = :userId ORDER BY snumber DESC LIMIT 20")
List<SLSNotification> getUserIdforManage(@Param("userId") String userId);

或者

另外,如果您想利用Spring Data JPA的便捷功能, 您可以通过适当的方法命名来实现。

List<SLSNotification> findByUserIdOrderBySNumber(@Param("userId") String userId, Pageable pageable);
如果您还不知道,Spring Data JPA会从方法名称构建查询。很神奇,对吗?为了更好地理解,请阅读这份文档
现在只需这样调用该方法:
Pageable topTwenty = PageRequest.of(0, 20);
List<SLSNotification> notifications = repository.findByUserIdOrderBySNumber("101", topTwenty);

此外,如果您正在使用Java 8

您可以选择在接口中使用默认方法,使生活变得更加轻松。

 List<SLSNotification> findByUserIdOrderBySNumber(@Param("userId") String userId, Pageable pageable);

 default List<User> findTop20ByUserIdOrderBySNumber(String userId) {
    return findByUserIdOrderBySNumber(userId, PageRequest.of(0,20));
 }

1
"limit" 是一种 SQL 语句。它在工作台中显然可以使用。 - Shafin Mahmud
@ Shafin Mahmud,看一下这张图片。我想按项目编号添加降序并限制为1条。 - Nipun Vidarshana
告诉我一件事。你的应用程序对于我提到的查询是否返回相同的输出? - Shafin Mahmud
1
好的,很高兴听到这个消息。但是有其他更多的方法来完成同样的事情。请保持关注,我正在更新答案。 - Shafin Mahmud
你刚才提到了你的查询。但是出现了什么错误?它是在什么时候发生的?如果你想要绑定一个来自用户请求的变量,那么这就是从“控制器”中进行的操作。 - Shafin Mahmud
显示剩余23条评论

4

根据Spring Data JPA提供的通过方法名称创建查询的功能,您可以使用此功能。要了解更多支持的查询方法谓词关键字和修饰符,请查看此文档。

Optional<List<SLSNotification>> findTop20ByUserId(String id); 

或者
Optional<List<SLSNotification>> findFirst20ByUserId(String id); 

这将限制查询结果到结果集的前。

如果您想限制排序结果集,则可以在方法名称中使用 DescAscOrderBy 如下。

// return the first 20 records which are ordered by SNumber. If you want Asc order, no need to add that keyword since it is the default of `OrderBy` 
Optional<List<SLSNotification>> findFirst20ByUserIdOrderBySNumberDesc(String id);  

建议 -- 在查询像find, get这样的存在至少一个结果的情况下,使用Optional作为返回类型更加安全可靠。


1

我发现LIMIT只能与nativeQuery一起使用,而nativeQuery只能在某些情况下使用。

理想情况下,查询方法名可以像这样使用:

EntityA findTopByParamXAndParamYAndParamZOrderByIdDesc();

它将限制结果为一个实体(一条记录)

在我的情况下,由于我有一个内连接,我不能真正使用方法命名,我也会避免使用分页,因为它将逻辑委托给调用者。

我发现这个相当优雅的解决方案是在查询中使用MAX(a)

@Query(value = "SELECT MAX(a) FROM EntityA a " +
        "INNER JOIN EntityB b on a.Bid = b.id " +
        "WHERE b.paramY = :paramY " +
        "AND b.paramZ = :paramZ " +
        "AND a.paramX = :paramX " +
        "ORDER BY a.id DESC")
EntityA findLastEntityAByParamsXYZ(
        @Param("paramX") String paramX,
        @Param("paramY") String paramY,
        @Param("paramZ") String paramZ);

0

如果您不想在存储库方法名称中硬编码定义限制,您可以在调用存储库的服务中使用PagePageable

Page<Passenger> page = repository.findAll(
  PageRequest.of(0, 20, Sort.by(Sort.Direction.ASC, "seatNumber")));

更多示例请参见: https://www.baeldung.com/jpa-limit-query-results

0
public interface ICategoriaDao extends CrudRepository<Categoria, Long>{

    @Query(value="select * from categoria c order by nombre limit ?1 offset ?2", nativeQuery=true)
    public List<Categoria> findPagina(Integer limit,  Integer offset );
}

1
请记住,Stack Overflow 不仅旨在解决当前的问题,还要帮助未来的读者找到类似问题的解决方案,这需要理解底层代码。对于我们社区中的初学者和不熟悉语法的成员来说,这尤其重要。鉴于此,您能否编辑您的答案,包括您正在做什么以及为什么您认为这是最好的方法的解释 - Jeremy Caney

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接