NonUniqueResultException:JPARepository Spring 启动
NonUniqueResultException: JPARepository Spring boot
我将 SpringBoot
与 JPA
和 QueryDSL
一起使用。我写了一个 HQL
来从 table 中获取一些自定义记录,但它抛出了 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
代码或查询或Return类型有什么问题吗?不过,查询似乎工作正常。
您的查询结果无法映射到Map<LocalDate,Integer>
。
您可以尝试 return List<Object[]>
而不是 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<Object[]>
解析为你需要的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);
}
根据 Spring 数据文档,Map
不属于 Supported Query Return Types。
甚至 JPA(即使是 2 版本)也不支持 Map
作为 return 类型执行查询。
所以您有两种方法可以解决您的问题:
1) 将 Map
保留为 return 类型。在这种情况下,不要使用 Spring 数据功能,它可以让您免于编写样板代码。
相反:从 EntityManager
创建查询,执行它并应用 post 处理以将结果映射到 Map。
如果 Map
具有合理的大小并且您确实需要从您的存储库中检索 Map
,那么应该优先使用这种方式。
2) 不要 return a Map
作为 return 类型。
在这两种情况下,您都必须选择所执行查询的 return 类型。您有两种选择:
1) List<Object[]>
为 return 类型,但它不一定有意义,也不安全。
2) 表示行结构的自定义 class
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);
请注意,将 List
转换为 Map
在 Java 8 中非常直接:
List<LoanOfferStats> loanOfferStats = loanOfferRepository.getLastMonthLoans(...);
Map<LocalDate, Long> map =
loanOfferStats.stream()
.collect(Collectors.toMap(LoanOfferStats::getStartDate, LoanOfferStats::getCount));
我将 SpringBoot
与 JPA
和 QueryDSL
一起使用。我写了一个 HQL
来从 table 中获取一些自定义记录,但它抛出了 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
代码或查询或Return类型有什么问题吗?不过,查询似乎工作正常。
您的查询结果无法映射到Map<LocalDate,Integer>
。
您可以尝试 return List<Object[]>
而不是 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<Object[]>
解析为你需要的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);
}
根据 Spring 数据文档,Map
不属于 Supported Query Return Types。
甚至 JPA(即使是 2 版本)也不支持 Map
作为 return 类型执行查询。
所以您有两种方法可以解决您的问题:
1) 将 Map
保留为 return 类型。在这种情况下,不要使用 Spring 数据功能,它可以让您免于编写样板代码。
相反:从 EntityManager
创建查询,执行它并应用 post 处理以将结果映射到 Map。
如果 Map
具有合理的大小并且您确实需要从您的存储库中检索 Map
,那么应该优先使用这种方式。
2) 不要 return a Map
作为 return 类型。
在这两种情况下,您都必须选择所执行查询的 return 类型。您有两种选择:
1) List<Object[]>
为 return 类型,但它不一定有意义,也不安全。
2) 表示行结构的自定义 class
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);
请注意,将 List
转换为 Map
在 Java 8 中非常直接:
List<LoanOfferStats> loanOfferStats = loanOfferRepository.getLastMonthLoans(...);
Map<LocalDate, Long> map =
loanOfferStats.stream()
.collect(Collectors.toMap(LoanOfferStats::getStartDate, LoanOfferStats::getCount));