如何从 Spring Data JPA GROUP BY 查询返回自定义对象JPQL 查询解决方案本机查询解决方案

2022-08-31 07:15:44

我正在使用Spring Data JPA开发Spring Boot应用程序。我正在使用自定义JPQL查询按某个字段分组并获取计数。以下是我的存储库方法。

@Query(value = "select count(v) as cnt, v.answer from Survey v group by v.answer")
public List<?> findSurveyCount();

它正在工作,结果如下:

[
  [1, "a1"],
  [2, "a2"]
]

我想得到这样的东西:

[
  { "cnt":1, "answer":"a1" },
  { "cnt":2, "answer":"a2" }
]

我怎样才能做到这一点?


答案 1

JPQL 查询解决方案

JPA 规范中的 JPQL 查询支持此功能。

步骤 1:声明一个简单的 Bean 类

package com.path.to;

public class SurveyAnswerStatistics {
  private String answer;
  private Long   cnt;

  public SurveyAnswerStatistics(String answer, Long cnt) {
    this.answer = answer;
    this.count  = cnt;
  }
}

步骤 2:从存储库方法返回 Bean 实例

public interface SurveyRepository extends CrudRepository<Survey, Long> {
    @Query("SELECT " +
           "    new com.path.to.SurveyAnswerStatistics(v.answer, COUNT(v)) " +
           "FROM " +
           "    Survey v " +
           "GROUP BY " +
           "    v.answer")
    List<SurveyAnswerStatistics> findSurveyCount();
}

重要提示

  1. 确保提供 Bean 类的完全限定路径,包括包名称。例如,如果调用了 Bean 类并且它位于包中,则 Bean 的完全限定路径将为 。简单地提供将不起作用(除非bean类在默认包中)。MyBeancom.path.tocom.path.to.MyBeanMyBean
  2. 确保使用关键字调用 Bean 类构造函数。 将工作,而不会。newSELECT new com.path.to.MyBean(...)SELECT com.path.to.MyBean(...)
  3. 确保以与 Bean 构造函数中预期完全相同的顺序传递属性。尝试以不同的顺序传递属性将导致异常。
  4. 确保查询是有效的 JPA 查询,即它不是本机查询。,或 ,或 将起作用,而将不起作用。这是因为本机查询无需修改即可传递到 JPA 提供程序,并且是针对底层 RDBMS 执行的。由于 和 不是有效的 SQL 关键字,因此 RDBMS 会引发异常。@Query("SELECT ...")@Query(value = "SELECT ...")@Query(value = "SELECT ...", nativeQuery = false)@Query(value = "SELECT ...", nativeQuery = true)newcom.path.to.MyBean

本机查询解决方案

如上所述,语法是 JPA 支持的机制,适用于所有 JPA 提供程序。但是,如果查询本身不是 JPA 查询,也就是说,它是本机查询,则语法将不起作用,因为查询直接传递到底层 RDBMS,而底层 RDBMS 不理解关键字,因为它不是 SQL 标准的一部分。new ...new ...new

在这种情况下,需要用Spring数据投影接口替换Bean类。

步骤 1:声明投影接口

package com.path.to;

public interface SurveyAnswerStatistics {
  String getAnswer();

  int getCnt();
}

步骤 2:从查询中返回投影属性

public interface SurveyRepository extends CrudRepository<Survey, Long> {
    @Query(nativeQuery = true, value =
           "SELECT " +
           "    v.answer AS answer, COUNT(v) AS cnt " +
           "FROM " +
           "    Survey v " +
           "GROUP BY " +
           "    v.answer")
    List<SurveyAnswerStatistics> findSurveyCount();
}

使用 SQL 关键字将结果字段映射到投影属性,以实现明确的映射。AS


答案 2

此 SQL 查询返回 List< Object[] >返回。

你可以这样做:

 @RestController
 @RequestMapping("/survey")
 public class SurveyController {

   @Autowired
   private SurveyRepository surveyRepository;

     @RequestMapping(value = "/find", method =  RequestMethod.GET)
     public Map<Long,String> findSurvey(){
       List<Object[]> result = surveyRepository.findSurveyCount();
       Map<Long,String> map = null;
       if(result != null && !result.isEmpty()){
          map = new HashMap<Long,String>();
          for (Object[] object : result) {
            map.put(((Long)object[0]),object[1]);
          }
       }
     return map;
     }
 }

推荐