@OrderBy批注中的JPA /休眠CASE引发异常:意外令牌:CASE

时间:2020-01-04 01:32:53

标签: hibernate jpa sql-order-by case jpql

我无法让@OrderBy @OneToMany上的List与JPA / Hibernate一起使用。

这是表映射:

俱乐部实体:

@Entity
@Table(name = "Clubs")
public class Club implements Serializable
{
    private static final long serialVersionUID = 1L;

    @Id
    @Column
    private Integer id;

    ...

    @OrderBy("SUBSTRING( teamTypeCode, 1, 1) ASC, CASE WHEN SUBSTRING( teamTypeCode, 1, 1 ) = 'O' THEN -CAST(SUBSTRING( teamTypeCode, 2, 2 ) AS DECIMAL) ELSE CAST(SUBSTRING( teamTypeCode, 2, 2 ) AS DECIMAL) END DESC, SUBSTRING( teamTypeCode, 4, 1 ) DESC, ordinalNbr")
    @OneToMany(mappedBy = "club")
    private List<Team> teams;

    ...
}

团队实体:

@Entity
@Table(name = "Teams")
@IdClass(TeamId.class)
public class Team implements Serializable
{
    @Id
    @Column(name = "club_id")
    private Integer clubId;

    @Id
    @Column(name = "team_type_code")
    private String teamTypeCode;

    @Id
    @Column(name = "ordinal_nbr")
    private Integer ordinalNbr;

    ...
}

一个俱乐部有多支球队,没什么特别的。

但是,我希望他们先按20岁以上的老年人分类,然后按30岁以上的老年人,35岁以上的老年人分类,...直至65岁以上的老年人分类,然后按20岁以下,18岁以下的青少年分类,直到08以下。

在SQL中,我可以使用查询来获得此信息:

SELECT *, SUBSTRING( team_type_code, 1, 1 ), SUBSTRING( team_type_code, 2, 2 ), SUBSTRING( team_type_code, 4, 1 ), ordinal_nbr
FROM bbstats.teams
WHERE club_id = 101
ORDER BY SUBSTRING( team_type_code, 1, 1 ) ASC,
         CASE WHEN SUBSTRING( team_type_code, 1, 1 ) = 'O'
              THEN -CAST(SUBSTRING( team_type_code, 2, 2 ) AS DECIMAL)
              ELSE CAST(SUBSTRING( team_type_code, 2, 2 ) AS DECIMAL)
         END DESC,
         SUBSTRING( team_type_code, 4, 1 ) DESC,
         ordinal_nbr;

第2个order by子句值得关注。我在这里所做的就是从4个字母的代码(例如O20M)中获取第一个字符(表示OVER 20 MALE),如果这表示“ over”,则取反int-cast值,否则将int-cast值作为一种排序DESC。

在(My)SQL中,它可以正常工作(您可以在前三列中看到真实数据):

enter image description here

但是在Hibernate 5.3.6中,将其翻译为@OrderBy注释:

@OrderBy("SUBSTRING( teamTypeCode, 1, 1) ASC, CASE WHEN SUBSTRING( teamTypeCode, 1, 1 ) = 'O' THEN -CAST(SUBSTRING( teamTypeCode, 2, 2 ) AS DECIMAL) ELSE CAST(SUBSTRING( teamTypeCode, 2, 2 ) AS DECIMAL) END DESC, SUBSTRING( teamTypeCode, 4, 1 ) DESC, ordinalNbr")

在启动服务器时给我一个例外:

01:50:29,345 ERROR [stderr] (ServerService Thread Pool -- 72) line 1:37: unexpected token: CASE

01:50:29,354 INFO  [org.hibernate.orm.beans] (ServerService Thread Pool -- 72) HHH10005004: Stopping BeanContainer : org.hibernate.resource.beans.container.internal.CdiBeanContainerExtendedAccessImpl@24248b3
01:50:29,355 INFO  [org.hibernate.service.internal.AbstractServiceRegistryImpl] (ServerService Thread Pool -- 72) HHH000369: Error stopping service [class org.hibernate.resource.beans.internal.ManagedBeanRegistryImpl] : java.lang.NullPointerException
01:50:29,355 ERROR [org.jboss.msc.service.fail] (ServerService Thread Pool -- 72) MSC000001: Failed to start service jboss.persistenceunit."bbstats-0.8.war#BBStatsPU": org.jboss.msc.service.StartException in service jboss.persistenceunit."bbstats-0.8.war#BBStatsPU": javax.persistence.PersistenceException: [PersistenceUnit: BBStatsPU] Unable to build Hibernate SessionFactory
    at org.jboss.as.jpa.service.PersistenceUnitServiceImpl$1$1.run(PersistenceUnitServiceImpl.java:195)
    at org.jboss.as.jpa.service.PersistenceUnitServiceImpl$1$1.run(PersistenceUnitServiceImpl.java:125)
    at org.wildfly.security.manager.WildFlySecurityManager.doChecked(WildFlySecurityManager.java:650)
    at org.jboss.as.jpa.service.PersistenceUnitServiceImpl$1.run(PersistenceUnitServiceImpl.java:209)
    at org.jboss.threads.ContextClassLoaderSavingRunnable.run(ContextClassLoaderSavingRunnable.java:35)
    at org.jboss.threads.EnhancedQueueExecutor.safeRun(EnhancedQueueExecutor.java:1985)
    at org.jboss.threads.EnhancedQueueExecutor$ThreadBody.doRunTask(EnhancedQueueExecutor.java:1487)
    at org.jboss.threads.EnhancedQueueExecutor$ThreadBody.run(EnhancedQueueExecutor.java:1378)
    at java.lang.Thread.run(Thread.java:748)
    at org.jboss.threads.JBossThread.run(JBossThread.java:485)
Caused by: javax.persistence.PersistenceException: [PersistenceUnit: BBStatsPU] Unable to build Hibernate SessionFactory
    at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.persistenceException(EntityManagerFactoryBuilderImpl.java:1016)
    at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.build(EntityManagerFactoryBuilderImpl.java:942)
    at org.jboss.as.jpa.hibernate5.TwoPhaseBootstrapImpl.build(TwoPhaseBootstrapImpl.java:44)
    at org.jboss.as.jpa.service.PersistenceUnitServiceImpl$1$1.run(PersistenceUnitServiceImpl.java:167)
    ... 9 more
Caused by: org.hibernate.MappingException: Could not get constructor for org.hibernate.persister.collection.OneToManyPersister
    at org.hibernate.persister.internal.PersisterFactoryImpl.createCollectionPersister(PersisterFactoryImpl.java:178)
    at org.hibernate.persister.internal.PersisterFactoryImpl.createCollectionPersister(PersisterFactoryImpl.java:140)
    at org.hibernate.metamodel.internal.MetamodelImpl.initialize(MetamodelImpl.java:198)
    at org.hibernate.internal.SessionFactoryImpl.<init>(SessionFactoryImpl.java:295)
    at org.hibernate.boot.internal.SessionFactoryBuilderImpl.build(SessionFactoryBuilderImpl.java:467)
    at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.build(EntityManagerFactoryBuilderImpl.java:939)
    ... 11 more
Caused by: org.hibernate.HibernateException: Unable to parse order-by fragment
    at org.hibernate.sql.ordering.antlr.OrderByFragmentTranslator.translate(OrderByFragmentTranslator.java:55)
    at org.hibernate.sql.Template.translateOrderBy(Template.java:724)
    at org.hibernate.persister.collection.AbstractCollectionPersister.<init>(AbstractCollectionPersister.java:556)
    at org.hibernate.persister.collection.OneToManyPersister.<init>(OneToManyPersister.java:69)
    at sun.reflect.GeneratedConstructorAccessor53.newInstance(Unknown Source)
    at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
    at java.lang.reflect.Constructor.newInstance(Constructor.java:423)
    at org.hibernate.persister.internal.PersisterFactoryImpl.createCollectionPersister(PersisterFactoryImpl.java:152)
    ... 16 more
Caused by: java.lang.NullPointerException
    at org.hibernate.sql.ordering.antlr.OrderByFragmentParser.postProcessSortSpecification(OrderByFragmentParser.java:251)
    at org.hibernate.sql.ordering.antlr.GeneratedOrderByFragmentParser.sortSpecification(GeneratedOrderByFragmentParser.java:314)
    at org.hibernate.sql.ordering.antlr.GeneratedOrderByFragmentParser.orderByFragment(GeneratedOrderByFragmentParser.java:198)
    at org.hibernate.sql.ordering.antlr.OrderByFragmentTranslator.translate(OrderByFragmentTranslator.java:49)
    ... 23 more

01:50:29,355 ERROR [org.jboss.as.controller.management-operation] (Controller Boot Thread) WFLYCTL0013: Operation ("deploy") failed - address: ([("deployment" => "bbstats-0.8.war")]) - failure description: {"WFLYCTL0080: Failed services" => {"jboss.persistenceunit.\"bbstats-0.8.war#BBStatsPU\"" => "javax.persistence.PersistenceException: [PersistenceUnit: BBStatsPU] Unable to build Hibernate SessionFactory
    Caused by: javax.persistence.PersistenceException: [PersistenceUnit: BBStatsPU] Unable to build Hibernate SessionFactory
    Caused by: org.hibernate.MappingException: Could not get constructor for org.hibernate.persister.collection.OneToManyPersister
    Caused by: org.hibernate.HibernateException: Unable to parse order-by fragment
    Caused by: java.lang.NullPointerException"}}

但是根据How to Use CASE, WHEN in JPA,这应该可行。

问题

怎么了?是否有其他技巧可以通过@OrderBy完成?是虫子吗? (请注意,我仍然可以通过Comparator使用手动排序来解决该问题,但如果可能的话,我想在没有问题的情况下完成它)


编辑:

使用特定于Hibernate的注释(使用 SQL 子句)会导致相同的异常:

@org.hibernate.annotations.OrderBy( clause= "SUBSTRING( team_type_code, 1, 1 ) ASC, CASE WHEN SUBSTRING( team_type_code, 1, 1 ) = 'O' THEN -CAST(SUBSTRING( team_type_code, 2, 2 ) AS DECIMAL) ELSE CAST(SUBSTRING( team_type_code, 2, 2 ) AS DECIMAL) END DESC, SUBSTRING( team_type_code, 4, 1 ) DESC, ordinal_nbr" )

1 个答案:

答案 0 :(得分:0)

根据文档,您不能像平常那样使用OrderBy注释。 https://docs.oracle.com/javaee/7/api/javax/persistence/OrderBy.html

在您的示例中,它显示了如何在查询方案中使用。

编辑:查询数据时,您仍然可以使用“排序依据”,它应该可以工作,但是我不确定是否是您想要的。