代码之家  ›  专栏  ›  技术社区  ›  Pieter De Clercq pedrofb

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

  •  3
  • Pieter De Clercq pedrofb  · 技术社区  · 7 年前

    Spring JPA/Hibernate H2 . 我的应用程序有一个显示统计数据的页面,这样的统计数据的一个例子是我的用户的平均年龄。然而,当我试图用 JPQL ,我收到一个异常

    Result must not be null!
    

    为了简单起见,假设我将年龄存储为 integer User

    用户模型

    @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(); 正在引发异常。我试过替换函数 AVG 在查询方式中 COUNT 这和预期的一样。我也尝试过使用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 在空表上执行时。我通过修改查询(灵感来自 the answer to this question

    @Query("SELECT coalesce(AVG(u.age), 0) FROM #{#entityName} u")
    long averageAge();
    
    3 回复  |  直到 7 年前
        1
  •  2
  •   akourt    7 年前

    EmptyResultDataAccessException 当查询的结果至少应有一行(或元素),但未返回任何行(或元素)时,将引发异常。

    相关文档可以找到 here .

    我建议运行与此尝试运行的查询相同的查询,以便进一步验证此理论。好问题是怎么处理这个。

    你有两个选择。要么抓住 在您的调用点上发生异常,并直接在那里处理它,或者您可以有一个 ExceptionHandler 负责处理此类异常。

        2
  •  4
  •   Stefan van den Akker Raymond Hettinger    7 年前

    如果您使用Spring数据,并且如果您的方法返回 null @org.springframework.lang.Nullable 方法签名:

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

    /* 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... */
    

    我用的是弹簧靴版本 2.1.1.RELEASE 和弹簧数据 2.1.4.RELEASE .

        3
  •  0
  •   Stefan van den Akker Raymond Hettinger    7 年前

    我不完全确定,但我认为问题是因为返回long的类型,也许应该使用long包装,long不允许null,因为它是一个原语,请尝试更改为

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