繁体   English   中英

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

[英]Spring Data JPA aggregate functions on an empty resultset

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

Result must not be null!

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

用户模型

@Entity
public class User implements Identifiable<Long> {
    private int age;
    // more fields and methods, irrelevant
}

用户存储库

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

我似乎无法弄清楚为什么调用UserRepository#averageAge(); 抛出异常。 我已经尝试用COUNT替换查询中的函数AVG ,这表现得如预期的那样。 我也尝试在注释中使用SQL查询并设置nativeQuery = true ,但无济于事。 我可以通过获取所有用户并使用普通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

解决了

异常是由AVG()在空表上执行时返回null引起的。 我通过修改查询(灵感来自这个问题的答案 )修复了它,如下所示:

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

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

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

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

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

处理此问题的两种方法都应该没问题,您可以根据您的方案在每种方法之间进行选择。

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

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

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

/* org.springframework.data.repository.core.support.MethodInvocationValidator */

@Nullable
@Override
public Object invoke(@SuppressWarnings("null") MethodInvocation invocation) throws Throwable {
    /* ...snip... */

    if (result == null && !nullability.isNullableReturn()) {
        throw new EmptyResultDataAccessException("Result must not be null!", 1);
    }

    /* ...snip... */

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

我不完全确定,但我认为问题是因为返回的类型很长,也许你应该使用Long包装器,long不允许null因为它是原始的,试着改为

@Query("SELECT AVG(u.age) FROM #{#entityName} u")
Long averageAge();

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM