NonUniqueResultException: JPARepository 春季启动

Posted

技术标签:

【中文标题】NonUniqueResultException: JPARepository 春季启动【英文标题】:NonUniqueResultException: JPARepository Spring boot 【发布时间】:2018-12-11 13:00:23 【问题描述】:

我将SpringBootJPAQueryDSL 一起使用。我写了一个HQL 来从表中获取一些自定义记录,但它正在抛出Exception。下面我提到存储库的代码:

@Repository
public interface LoanOfferRepository extends JpaRepository<LoanOffer, Long>, QuerydslPredicateExecutor<LoanOffer> 

    @Query("select lo.startDate,count(*) from LoanOffer lo where lo.loan.fsp= :fsp and lo.startDate between :fromDate and :toDate Group by lo.startDate")
    public Map<LocalDate,Integer> getLastMonthLoans(@Param("fsp")Fsp fsp,@Param("fromDate")LocalDate fromDate,@Param("toDate")LocalDate toDate);

每当我调用此方法getLastMonthLoans() 时,我都会收到以下异常:

Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is org.springframework.dao.IncorrectResultSizeDataAccessException: query did not return a unique result: 9; nested exception is javax.persistence.NonUniqueResultException: query did not return a unique result: 9] with root cause

javax.persistence.NonUniqueResultException: query did not return a unique result: 9

代码或查询或返回类型有什么问题吗?查询似乎工作正常。

【问题讨论】:

你应该使用projections。请检查我的答案1,2 如何从 repo 返回任意对象。 【参考方案1】:

您的查询结果无法映射到Map&lt;LocalDate,Integer&gt;

您可以尝试返回List&lt;Object[]&gt; 而不是Map

@Query("select lo.startDate,count(*) from LoanOffer lo where lo.loan.fsp= :fsp and lo.startDate between :fromDate and :toDate Group by lo.startDate")
public List<Object[]> getLastMonthLoans(@Param("fsp")Fsp fsp,@Param("fromDate")LocalDate fromDate,@Param("toDate")LocalDate toDate);

然后将List&lt;Object[]&gt;解析成你需要的Map

这样:

Map<LocalDate, Integer> mappedResult = new HashMap<>();
List<Object[]> queryResult = loanOfferRepository.getLastMonthLoans(fsp, fromDate, toDate);
for (Object[] obj : queryResult ) 
    LocalDate ld = (LocalDate) obj[0];
    Integer count = (Integer) obj[1];
    mappedResult.put(ld, count);

【讨论】:

【参考方案2】:

根据 Spring Data 文档,Map 不属于 Supported Query Return Types。 甚至 JPA(甚至是 2 版本)也不支持 Map 作为执行查询中的返回类型。

所以你有两种方法可以解决你的问题:

1) 保留Map 作为返回类型。在这种情况下,不要使用 Spring Data 特性,它可以让您免于编写样板代码。 而是:从 EntityManager 创建查询,执行它并应用后处理将结果映射到 Map。 如果Map 具有合理的大小,并且您确实需要从存储库中检索Map,则应该优先使用这种方式。

2) 不要返回 Map 作为返回类型。

在这两种情况下,您都必须选择执行查询的返回类型。您大致有两种选择:

1) List&lt;Object[]&gt; 作为返回类型,但它不一定有意义,也不是类型安全的。

2) 表示行结构的自定义类

public class LoanOfferStats
  private LocalDate startDate;
  private Long count;

  public LoanOfferStats(LocalDate startDate, Long count) 
    this.startDate = startDate;
    this.count  = count;
  

  public LocalDate getStartDate()
     return startDate;
  

  public Long getCount()
     return count;
  


并注释您的方法,例如:

 @Query("select new fullpackage.LoanOfferStats(lo.startDate,count(*))
 from LoanOffer lo where lo.loan.fsp= :fsp and lo.startDate between
 :fromDate and :toDate Group by lo.startDate")
     public List<LoanOfferStats> getLastMonthLoans(@Param("fsp")Fsp fsp,@Param("fromDate")LocalDate fromDate,@Param("toDate")LocalDate
 toDate);

请注意,在 Java 8 中将 List 转换为 Map 非常直接:

List<LoanOfferStats> loanOfferStats = loanOfferRepository.getLastMonthLoans(...);
Map<LocalDate, Long> map = 
        loanOfferStats.stream()
                      .collect(Collectors.toMap(LoanOfferStats::getStartDate, LoanOfferStats::getCount));  

【讨论】:

以上是关于NonUniqueResultException: JPARepository 春季启动的主要内容,如果未能解决你的问题,请参考以下文章

如何解决此问题 org.hibernate.NonUniqueResultException:查询未返回唯一结果:4

查询未返回唯一结果:4;嵌套异常是 javax.persistence.NonUniqueResultException:查询没有返回唯一结果:4

result returns more than one elements 异常错误

Hibernate - 如何在 JSP 表中显示对象列表?