JPA查询验证在subselect失败,即使它在控制台中工作

时间:2017-11-02 11:00:18

标签: spring validation jpa spring-data jpql

情况:

我有以下jpa查询,它在IntelliJ jpa-ql控制台中完美运行。我已将其添加为图片,以便可以看到代码突出显示,从而显示实际错误:

select 
    run1.someAttribute1 AS someAttribute1, 
    run1.someAttribute2 AS someAttribute2, 
    run1.someAttribute3 AS someAttribute3, 
    (select
        sum(function('timestampdiff', SECOND, run2.runStartTime, run2.runEndTime)) 
        from runTable AS run2 
        where run2.anotherAttribute1 = run1.anotherAttribute1 
        and run2.anotherAttribute2 = run1.someAttribute2 
        and run2.anotherAttribute3 = run1.someAttribute3
    ) AS runtime, 
    sum(
        case when type(event) = SomeEvent and event.someType = '...' then 1   
        else 0 end
    ) AS numberOfSomething1,
    sum(
        case when type(event) = SomeEvent and event.someType = '...' then 1     
        else 0 end
    ) AS numberOfSomething2, 
    sum(
        case when type(event) = SomeEvent and event.someType = '...' then 1 
        else 0 end
    ) AS numberOfSomething3, 
    sum(
        case when type(event) = SomeEvent and event.someType = '...' then 1 
        else 0 end
    ) AS numberOfSomething4, 
    sum(
        case when type(event) = SomeEvent2 then 1 
        else 0 end
    ) AS numberOfSomething5from runTable AS run1 
left join run1.events AS event 
group by someAttribute1, someAttribute2, someAttribute3 
order by 
    max(function('right', function('left', someAttribute1, 8), 3)) desc,    
    someAttribute2 desc, 
    someAttribute3 desc

JPA Query with subselect validation error

如果在jpa-ql控制台中运行,则返回以下结果:

Right result with sub select

第三列是以秒为单位的runTime,如果使用subselect查询完成则是正确的。如果我重构subselect以使用run1别名,则返回错误的结果。我认为分组已经包含了正确的runTime,但显然我错了:

select 
    run1.someAttribute1 AS someAttribute1, 
    run1.someAttribute2 AS someAttribute2, 
    run1.someAttribute3 AS someAttribute3, 
    sum(
       function('timestampdiff', SECOND, run1.runStartTime, run1.runEndTime)
    ) AS runtime, 
    sum(case when type(event) = SomeEvent and event.someType = '...' then 1 else 0 end) AS numberOfSomething1,
    sum(case when type(event) = SomeEvent and event.someType = '...' then 1 else 0 end) AS numberOfSomething2, 
    sum(case when type(event) = SomeEvent and event.someType = '...' then 1 else 0 end) AS numberOfSomething3, 
    sum(case when type(event) = SomeEvent and event.someType = '...' then 1 else 0 end) AS numberOfSomething4, 
    sum(case when type(event) = SomeEvent2 then 1 else 0 end) AS numberOfSomething5from runTable AS run1 
left join run1.events AS event 
group by someAttribute1, someAttribute2, someAttribute3 
order by max(function('right', function('left', someAttribute1, 8), 3)) desc,
    someAttribute2 desc, 
    someAttribute3 desc

Wrong result with alias from the FROM clause

问题

主要区别在于,第一个jpa查询在启动spring boot应用程序时抛出错误,而重构的jpa查询则没有:

Caused by: java.lang.IllegalArgumentException: Validation failed for query for method public abstract java.util.List someClass.someMethod()
at org.springframework.data.jpa.repository.query.SimpleJpaQuery.validateQuery(SimpleJpaQuery.java:92) ~[spring-data-jpa-1.11.8.RELEASE.jar:?]
at org.springframework.data.jpa.repository.query.SimpleJpaQuery.<init>(SimpleJpaQuery.java:62) ~[spring-data-jpa-1.11.8.RELEASE.jar:?]
at org.springframework.data.jpa.repository.query.JpaQueryFactory.fromMethodWithQueryString(JpaQueryFactory.java:72) ~[spring-data-jpa-1.11.8.RELEASE.jar:?]
at org.springframework.data.jpa.repository.query.JpaQueryFactory.fromQueryAnnotation(JpaQueryFactory.java:53) ~[spring-data-jpa-1.11.8.RELEASE.jar:?]
at org.springframework.data.jpa.repository.query.JpaQueryLookupStrategy$DeclaredQueryLookupStrategy.resolveQuery(JpaQueryLookupStrategy.java:144) ~[spring-data-jpa-1.11.8.RELEASE.jar:?]
at org.springframework.data.jpa.repository.query.JpaQueryLookupStrategy$CreateIfNotFoundQueryLookupStrategy.resolveQuery(JpaQueryLookupStrategy.java:211) ~[spring-data-jpa-1.11.8.RELEASE.jar:?]
at org.springframework.data.jpa.repository.query.JpaQueryLookupStrategy$AbstractQueryLookupStrategy.resolveQuery(JpaQueryLookupStrategy.java:77) ~[spring-data-jpa-1.11.8.RELEASE.jar:?]
at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.<init>(RepositoryFactorySupport.java:436) ~[spring-data-commons-1.13.8.RELEASE.jar:?]
at org.springframework.data.repository.core.support.RepositoryFactorySupport.getRepository(RepositoryFactorySupport.java:221) ~[spring-data-commons-1.13.8.RELEASE.jar:?]
at org.springframework.data.repository.core.support.RepositoryFactoryBeanSupport.initAndReturn(RepositoryFactoryBeanSupport.java:277) ~[spring-data-commons-1.13.8.RELEASE.jar:?]
at org.springframework.data.repository.core.support.RepositoryFactoryBeanSupport.afterPropertiesSet(RepositoryFactoryBeanSupport.java:263) ~[spring-data-commons-1.13.8.RELEASE.jar:?]
at org.springframework.data.jpa.repository.support.JpaRepositoryFactoryBean.afterPropertiesSet(JpaRepositoryFactoryBean.java:101) ~[spring-data-jpa-1.11.8.RELEASE.jar:?]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1687) ~[spring-beans-4.3.10.RELEASE.jar:4.3.10.RELEASE]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1624) ~[spring-beans-4.3.10.RELEASE.jar:4.3.10.RELEASE]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:555) ~[spring-beans-4.3.10.RELEASE.jar:4.3.10.RELEASE]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:483) ~[spring-beans-4.3.10.RELEASE.jar:4.3.10.RELEASE]
at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:306) ~[spring-beans-4.3.10.RELEASE.jar:4.3.10.RELEASE]
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230) ~[spring-beans-4.3.10.RELEASE.jar:4.3.10.RELEASE]
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:302) ~[spring-beans-4.3.10.RELEASE.jar:4.3.10.RELEASE]
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:202) ~[spring-beans-4.3.10.RELEASE.jar:4.3.10.RELEASE]
at org.springframework.beans.factory.config.DependencyDescriptor.resolveCandidate(DependencyDescriptor.java:208) ~[spring-beans-4.3.10.RELEASE.jar:4.3.10.RELEASE]
at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1138) ~[spring-beans-4.3.10.RELEASE.jar:4.3.10.RELEASE]
at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1066) ~[spring-beans-4.3.10.RELEASE.jar:4.3.10.RELEASE]
at org.springframework.beans.factory.support.ConstructorResolver.resolveAutowiredArgument(ConstructorResolver.java:835) ~[spring-beans-4.3.10.RELEASE.jar:4.3.10.RELEASE]
at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:741) ~[spring-beans-4.3.10.RELEASE.jar:4.3.10.RELEASE]
... 17 more

看起来spring数据不能处理select子句中逗号后面的左括号(参见1),即使实际查询确实有效。

问题

有没有办法解决这个问题或重写子选择查询?

使用spring-data版本1.11.8进行查询验证

1 个答案:

答案 0 :(得分:0)

我不知道你在控制台中执行了什么,但这不是你发布的查询,一旦你像我那样格式化它就会变得很明显。

在这两种情况下,from之前的left join前面都缺少空格。

另外,我认为子选择应该以关键字select开头。