JPQL/HQL and JPA/Hibernate: boolean expression in

2019-07-03 23:42发布

问题:

I have a JPQL statement to return a schedule of sports games:

SELECT NEW com.kawoolutions.bbstats.view.ScheduleGameLine(
    ga.id                                                                                           AS gid
  , ga.scheduledTipoff                                                                              AS scheduledtipoff
  ...
  , sch.finalScore                                                                                  AS homefinalscore
  , sca.finalScore                                                                                  AS awayfinalscore
  , sch.finalScore IS NOT NULL AND sca.finalScore IS NOT NULL                              AS hasfinalscore
)

I want the last expression (boolean) to evaluate to a boolean to indicate whether a game's final score has been completely reported or not (two entities of type Score, here sch and sca for score home and away). However, Hibernate fails with an exception:

11.02.2011 18:40:16 org.hibernate.hql.ast.ErrorCounter reportError
SCHWERWIEGEND: <AST>:17:32: unexpected AST node: AND
Exception in thread "main" java.lang.NullPointerException
    at org.hibernate.hql.ast.HqlSqlWalker.setAlias(HqlSqlWalker.java:1000)
    at org.hibernate.hql.antlr.HqlSqlBaseWalker.aliasedSelectExpr(HqlSqlBaseWalker.java:2381)
    at org.hibernate.hql.antlr.HqlSqlBaseWalker.constructor(HqlSqlBaseWalker.java:2505)
    at org.hibernate.hql.antlr.HqlSqlBaseWalker.selectExpr(HqlSqlBaseWalker.java:2256)
    at org.hibernate.hql.antlr.HqlSqlBaseWalker.selectExprList(HqlSqlBaseWalker.java:2121)
    at org.hibernate.hql.antlr.HqlSqlBaseWalker.selectClause(HqlSqlBaseWalker.java:1522)
    at org.hibernate.hql.antlr.HqlSqlBaseWalker.query(HqlSqlBaseWalker.java:593)
    at org.hibernate.hql.antlr.HqlSqlBaseWalker.selectStatement(HqlSqlBaseWalker.java:301)
    at org.hibernate.hql.antlr.HqlSqlBaseWalker.statement(HqlSqlBaseWalker.java:244)
    at org.hibernate.hql.ast.QueryTranslatorImpl.analyze(QueryTranslatorImpl.java:254)
    at org.hibernate.hql.ast.QueryTranslatorImpl.doCompile(QueryTranslatorImpl.java:185)
    at org.hibernate.hql.ast.QueryTranslatorImpl.compile(QueryTranslatorImpl.java:136)
    at org.hibernate.engine.query.HQLQueryPlan.<init>(HQLQueryPlan.java:101)
    at org.hibernate.engine.query.HQLQueryPlan.<init>(HQLQueryPlan.java:80)
    at org.hibernate.engine.query.QueryPlanCache.getHQLQueryPlan(QueryPlanCache.java:124)
    at org.hibernate.impl.AbstractSessionImpl.getHQLQueryPlan(AbstractSessionImpl.java:156)
    at org.hibernate.impl.AbstractSessionImpl.createQuery(AbstractSessionImpl.java:135)
    at org.hibernate.impl.SessionImpl.createQuery(SessionImpl.java:1770)
    at org.hibernate.ejb.AbstractEntityManagerImpl.createQuery(AbstractEntityManagerImpl.java:272)
    at com.kawoolutions.bbstats.Main.executeJpqlStatement(Main.java:167)
    at com.kawoolutions.bbstats.Main.main(Main.java:154)

When surrounding the last expression with a CASE WHEN to return either TRUE or FALSE I get the results I expect:

SELECT NEW com.kawoolutions.bbstats.view.ScheduleGameLine(
    ga.id                                                                                           AS gid
  , ga.scheduledTipoff                                                                              AS scheduledtipoff
  ...
  , sch.finalScore                                                                                  AS homefinalscore
  , sca.finalScore                                                                                  AS awayfinalscore
  , CASE WHEN sch.finalScore IS NOT NULL AND sca.finalScore IS NOT NULL THEN TRUE ELSE FALSE END    AS hasfinalscore
  )

I'd really like to know why this isn't working with a CASE WHEN. What's wrong here? Is it me? Is it JPA? Is it Hibernate? Bug?

回答1:

It looks like a specified behaviour. JPA doesn't allow conditional expressions in SELECT clause at all, though allows CASE expressions.

Here is a relevant part of JPQL grammar from the JPA Specification:

select_expression ::=
    single_valued_path_expression |
    scalar_expression |
    aggregate_expression |
    identification_variable |
    OBJECT(identification_variable) |
    constructor_expression

constructor_expression ::=
    NEW constructor_name ( constructor_item {, constructor_item}* )

constructor_item ::=
    single_valued_path_expression |
    scalar_expression |
    aggregate_expression |
    identification_variable

scalar_expression ::=
    simple_arithmetic_expression |
    string_primary |
    enum_primary |
    datetime_primary |
    boolean_primary |
    case_expression |
    entity_type_expression