JPA/Hibernate @OrderBy 注释中的 CASE 抛出异常:意外标记:CASE
JPA/Hibernate CASE in @OrderBy annotation throws exception: unexpected token: CASE
我无法在 @OneToMany
List
上使用 @OrderBy
与 JPA/Hibernate 一起工作。
这是 table 映射:
俱乐部实体:
@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;
第二个 order by 子句很有趣。我在这里所做的就是从像 O20M(意思是 OVER 20 MALE)这样的 4 字母代码中获取第一个字符,如果这意味着 "over" 则取反 int-cast 值,否则只需按原样获取 int-cast 值排序 DESC.
在 (My)SQL 中没有问题(您可以在此处的前 3 列中看到真实数据):
然而,在 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.run(PersistenceUnitServiceImpl.java:195)
at org.jboss.as.jpa.service.PersistenceUnitServiceImpl.run(PersistenceUnitServiceImpl.java:125)
at org.wildfly.security.manager.WildFlySecurityManager.doChecked(WildFlySecurityManager.java:650)
at org.jboss.as.jpa.service.PersistenceUnitServiceImpl.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.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"}}
然而,根据 ,这应该有效。
问题
怎么了?有没有其他技巧可以通过 @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" )
根据文档,您不能像以前那样使用 OrderBy 注释。
https://docs.oracle.com/javaee/7/api/javax/persistence/OrderBy.html
在你的例子中,它展示了如何在查询场景中使用。
编辑:您仍然可以在查询数据时使用 'order by',它应该可以工作,但我不确定它是否是您想要的。
我无法在 @OneToMany
List
上使用 @OrderBy
与 JPA/Hibernate 一起工作。
这是 table 映射:
俱乐部实体:
@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;
第二个 order by 子句很有趣。我在这里所做的就是从像 O20M(意思是 OVER 20 MALE)这样的 4 字母代码中获取第一个字符,如果这意味着 "over" 则取反 int-cast 值,否则只需按原样获取 int-cast 值排序 DESC.
在 (My)SQL 中没有问题(您可以在此处的前 3 列中看到真实数据):
然而,在 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.run(PersistenceUnitServiceImpl.java:195)
at org.jboss.as.jpa.service.PersistenceUnitServiceImpl.run(PersistenceUnitServiceImpl.java:125)
at org.wildfly.security.manager.WildFlySecurityManager.doChecked(WildFlySecurityManager.java:650)
at org.jboss.as.jpa.service.PersistenceUnitServiceImpl.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.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"}}
然而,根据
问题
怎么了?有没有其他技巧可以通过 @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" )
根据文档,您不能像以前那样使用 OrderBy 注释。 https://docs.oracle.com/javaee/7/api/javax/persistence/OrderBy.html
在你的例子中,它展示了如何在查询场景中使用。
编辑:您仍然可以在查询数据时使用 'order by',它应该可以工作,但我不确定它是否是您想要的。