【问题标题】:Hibernate/HQL/JPQL: what's wrong with a CASE WHEN ... THEN NULL ELSE ... END (ClassCastException)?Hibernate/HQL/JPQL:CASE WHEN ... THEN NULL ELSE ... END (ClassCastException) 有什么问题?
【发布时间】:2011-05-22 00:08:30
【问题描述】:

我在 SELECT 中有以下 JPQL/HQL sn-p

...
 MAX(CASE WHEN scf.finalScore = 20 OR scf.finalScore = 0 THEN NULL ELSE scf.finalScore END) AS hi,
 MIN(CASE WHEN scf.finalScore = 20 OR scf.finalScore = 0 THEN NULL ELSE scf.finalScore END) AS lo,
...

查找最高分和最低分。如果 (scf) 或对局的得分是 20 或 0,那么这是一场具有特殊结果的游戏,对于 MIN 和 MAX 将被忽略。

Hibernate 抛出异常:

Exception in thread "main" java.lang.ClassCastException: org.hibernate.hql.ast.tree.SqlNode cannot be cast to org.hibernate.hql.ast.tree.SelectExpression
    at org.hibernate.hql.ast.tree.CaseNode.getFirstThenNode(CaseNode.java:44)
    at org.hibernate.hql.ast.tree.CaseNode.getDataType(CaseNode.java:40)
    at org.hibernate.hql.ast.util.SessionFactoryHelper.findFunctionReturnType(SessionFactoryHelper.java:402)
    at org.hibernate.hql.ast.tree.AggregateNode.getDataType(AggregateNode.java:82)
    at org.hibernate.hql.ast.tree.ConstructorNode.resolveConstructorArgumentTypes(ConstructorNode.java:163)
    at org.hibernate.hql.ast.tree.ConstructorNode.prepare(ConstructorNode.java:141)
    at org.hibernate.hql.ast.HqlSqlWalker.processConstructor(HqlSqlWalker.java:996)
    at org.hibernate.hql.antlr.HqlSqlBaseWalker.selectExpr(HqlSqlBaseWalker.java:2260)
    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 tld.standalone.Main.executeJpqlStatement(Main.java:70)
    at tld.standalone.Main.main(Main.java:58)

怎么了?是我的代码吗?休眠错误?

问题似乎是 Hibernate 无法在 THEN 中处理 NULL:没有聚合函数的“CASE WHEN scf.finalScore IN (0, 20) THEN NULL ELSE scf.finalScore END ASplayscore”仍然抛出相同的问题例外。那么,这是一个 Hibernate 错误吗?

【问题讨论】:

    标签: hibernate null hql jpql case-when


    【解决方案1】:

    JPQL 不允许在聚合函数中使用 CASE,尽管 Hibernate 在其语法中没有限制它,因此在 AST 处理期间会引发异常。

    来自 JPA 规范:

    aggregate_expression ::=
        { AVG | MAX | MIN | SUM } ([DISTINCT] state_field_path_expression) |
        COUNT ([DISTINCT] identification_variable | state_field_path_expression |
            single_valued_object_path_expression)
    
    state_field_path_expression ::=
        general_identification_variable.{single_valued_object_field.}*state_field
    

    因此,对于这种逻辑,您需要一个原生 SQL 查询。

    【讨论】:

    • 我颠倒了布尔逻辑并将 NULL 放入 ELSE 以使其工作:MAX(CASE WHEN scf.finalScore NOT IN (0, 20) THEN scf.finalScore ELSE NULL END) AS hi。
    • 虽然您对 CASE 和聚合函数的评论是正确的,但它不能回答为什么 Hibernate 在 THEN 中存在 NULL 问题:“CASE WHEN scf.finalScore IN (0, 20) THEN NULL没有聚合函数的 ELSE scf.finalScore END AS playscore" 仍然会引发相同的异常。那么这是一个 Hibernate 错误吗?
    猜你喜欢
    • 1970-01-01
    • 2013-10-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-12-28
    • 1970-01-01
    • 1970-01-01
    • 2012-08-29
    相关资源
    最近更新 更多