空结果集上的 Spring Data JPA 聚合函数

Pie*_*rcq 6 java spring h2 spring-data spring-data-jpa

我正在做一个涉及Spring和的项目JPA/Hibernate。我的开发环境中使用的数据库驱动程序是H2. 我的应用程序有一个显示统计信息的页面,此类统计信息的一个示例是我的用户的平均年龄。但是,当我尝试使用 获取平均年龄时JPQL,我收到一个异常

Result must not be null!
Run Code Online (Sandbox Code Playgroud)

为简单起见,假设我将年龄存储为integer每个User对象的一个​​(在我的应用程序中这当然不是这种情况,但这对我的问题并不重要)。

用户模型

@Entity
public class User implements Identifiable<Long> {
    private int age;
    // more fields and methods, irrelevant
}
Run Code Online (Sandbox Code Playgroud)

用户存储库

@Repository
public interface UserRepository extends CrudRepository<User, Long> {
    @Query("SELECT AVG(u.age) FROM #{#entityName} u")
    long averageAge();
}
Run Code Online (Sandbox Code Playgroud)

我似乎无法弄清楚为什么调用UserRepository#averageAge();会引发异常。我已尝试将AVG查询中的函数替换为by ,COUNT并且其行为符合预期。我也尝试nativeQuery = true在注释中使用 SQL 查询和设置,但无济于事。我当然可以通过获取所有用户并用普通 Java 计算平均年龄来解决它,但这不会很有效。

堆栈跟踪:

Caused by: org.springframework.dao.EmptyResultDataAccessException: Result must not be null!
    at org.springframework.data.repository.core.support.MethodInvocationValidator.invoke(MethodInvocationValidator.java:102)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:185)
    at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:212)
    at com.sun.proxy.$Proxy150.averageAge(Unknown Source)
    at my.test.application.StatisticsRunner.run(StatisticsRunner.java:72)
at org.springframework.boot.SpringApplication.callRunner(SpringApplication.java:809)
    ... 30 more
Run Code Online (Sandbox Code Playgroud)

解决了

该异常是由在空表上执行时AVG()返回的事实引起的null。我通过修改查询(受到这个问题的答案的启发)来修复它,如下所示:

@Query("SELECT coalesce(AVG(u.age), 0) FROM #{#entityName} u")
long averageAge();
Run Code Online (Sandbox Code Playgroud)

Ste*_*ker 5

如果您使用 Spring Data,并且如果您的方法null在 Hibernate 找不到匹配项时返回,请确保添加@org.springframework.lang.Nullable到您的方法签名中:

public interface SomeRepositoryCustom {
    @org.springframework.lang.Nullable
    public Thing findOneThingByAttr(Attribute attr) {
        /* ...your logic here... */
    }
}
Run Code Online (Sandbox Code Playgroud)

这是因为 Spring Data 会检查您的方法的可空性,如果缺少注释,它将强制您始终需要返回一个对象:

public interface SomeRepositoryCustom {
    @org.springframework.lang.Nullable
    public Thing findOneThingByAttr(Attribute attr) {
        /* ...your logic here... */
    }
}
Run Code Online (Sandbox Code Playgroud)

我使用了 Spring Boot 版本2.1.1.RELEASE和 Spring Data 2.1.4.RELEASE


Ari*_*tex 2

EmptyResultDataAccessException当查询结果预计至少有一行(或元素)但没有返回时,似乎会引发异常。

可以在此处找到有关此内容的相关文档。

我建议运行与此尝试运行的相同查询,以进一步验证该理论。现在的好问题是如何处理这个问题。

你有两个选择。要么EmptyResultDataAccessException在调用点捕获异常并直接在那里处理它,要么您可以有一个ExceptionHandler负责处理此类异常的任务。

两种处理方法都应该没问题,您可以根据您的情况进行选择。