Hibernate/HQL/JPQL: что не так с CASE WHEN THEN NULL ELSE END (ClassCastException)?

У меня есть следующий фрагмент JPQL/HQL в SELECT

...
 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, то это игра с особым исходом, который следует игнорировать для МИН. и МАКС.

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 не может обработать NULL внутри THEN: «CASE WHEN scf.finalScore IN (0, 20) THEN NULL ELSE scf.finalScore END AS playscore» без агрегатной функции по-прежнему вызывает то же исключение. Итак, это ошибка Hibernate?


person Kawu    schedule 08.12.2010    source источник


Ответы (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-запрос для такой логики.

person axtavt    schedule 08.12.2010
comment
Я перевернул логическую логику и поместил NULL в ELSE, чтобы заставить ее работать: MAX(CASE WHEN scf.finalScore NOT IN (0, 20) THEN scf.finalScore ELSE NULL END) AS hi. - person Kawu; 08.12.2010
comment
Хотя ваши замечания о CASE и агрегатных функциях верны, они не отвечают, почему Hibernate имеет проблемы с NULL в THEN: a CASE WHEN scf.finalScore IN (0, 20) THEN NULL ELSE scf.finalScore END AS playscore без агрегата функция по-прежнему выдает то же исключение. Так это ошибка Hibernate? - person Kawu; 09.12.2010