多级连接的 Hibernate 5 迁移问题 table Hibernate 5.4 DiscriminatorColumn 的继承

Hibernate 5 migration Issue with Multilevel Joined table Inheritance with Hibernate 5.4 DiscriminatorColumn

我正在将遗留 Hibernate 项目从版本 4.1 迁移到 5.4。该代码使用专用 DiscriminatorColumn Multilevel Joined table 继承。该代码在 Hibernate 4 中运行良好,但在 Hibernate 5 中抛出错误。

In-Short class 层级 就像:

而且,代码 看起来像:

一级超级class

@Entity
@Table(name="VideoTag")
@Inheritance(strategy = InheritanceType.JOINED)
@DiscriminatorColumn(name = "VideoTagType", discriminatorType = DiscriminatorType.INTEGER)
@DiscriminatorOptions(force=true)
public abstract class VideoTag implements Cloneable {
    
    @Id
    @Column(name = "AdTagId")
    private Long adTagId;

    @Column(name = "VideoTagType")
    @Type(type = "enum_pub_video_tag_type")
    private VideoTagType videoTagType;
    
    //Non-important columns

    //Accessors 
}

二级classes

简单子class:
@Entity
@DiscriminatorValue(value = "2")
@Table(name = "OutstreamVideoTag")
public class OutStreamVideoTag extends VideoTag implements Cloneable {
        
    //Non-important columns

    //Accessors 
}

复杂sub-class/Second级超级class
@Entity
@DiscriminatorValue(value = "1")
@Table(name = "InStreamVideoTag")
@Inheritance(strategy = InheritanceType.JOINED)
@DiscriminatorColumn(name = "InstreamVideoTagType", discriminatorType = DiscriminatorType.INTEGER)
public abstract class InStreamVideoTag extends VideoTag implements Cloneable {

    @Column(name = "InstreamVideoTagType")
    @Type(type = "enum_pub_instream_video_tag_type")
    private InstreamVideoTagType instreamVideoTagType;
    
    //Non-important columns

    //Accessors 
    
}

最后一级子classes

@Entity
@DiscriminatorValue(value = "1")
@Table(name = "RegularInStreamVideoTag")
public class RegularInStreamVideoTag extends InStreamVideoTag implements Cloneable {
    //Non-important columns

    //Accessors 
}

@Entity
@DiscriminatorValue(value = "2")
@Table(name = "InAppInstreamVideoTag")
public class InAppInstreamVideoTag extends InStreamVideoTag implements Cloneable {
        
    //Non-important columns

    //Accessors 
}

错误

1. RegularInStreamVideoTag 实体的保存抛出以下错误:

[DEBUG][SQL,qtp88259764-236] - 
    insert 
    into
        VideoTag
        (PlayerType, VideoTagType, AdTagId) 
    values
        (?, 1, ?)
Hibernate: 
    insert 
    into
        VideoTag
        (PlayerType, VideoTagType, AdTagId) 
    values
        (?, 1, ?)
[DEBUG][SqlExceptionHelper,qtp88259764-236] - could not insert: [com.domain.businessobject.publisher.RegularInStreamVideoTag] [insert into VideoTag (PlayerType, VideoTagType, AdTagId) values (?, 1, ?)]
com.microsoft.sqlserver.jdbc.SQLServerException: The index 3 is out of range.
    at com.microsoft.sqlserver.jdbc.SQLServerException.makeFromDriverError(SQLServerException.java:234) ~[mssql-jdbc-9.2.1.jre11.jar:?]
    at com.microsoft.sqlserver.jdbc.SQLServerPreparedStatement.setterGetParam(SQLServerPreparedStatement.java:1115) ~[mssql-jdbc-9.2.1.jre11.jar:?]
    at com.microsoft.sqlserver.jdbc.SQLServerPreparedStatement.setValue(SQLServerPreparedStatement.java:1129) ~[mssql-jdbc-9.2.1.jre11.jar:?]
    at com.microsoft.sqlserver.jdbc.SQLServerPreparedStatement.setLong(SQLServerPreparedStatement.java:1429) ~[mssql-jdbc-9.2.1.jre11.jar:?]
    at com.zaxxer.hikari.pool.HikariProxyPreparedStatement.setLong(HikariProxyPreparedStatement.java) ~[HikariCP-3.4.5.jar:?]
    at org.hibernate.type.descriptor.sql.BigIntTypeDescriptor.doBind(BigIntTypeDescriptor.java:46) ~[hibernate-core-5.4.32.Final.jar:5.4.32.Final]
    at org.hibernate.type.descriptor.sql.BasicBinder.bind(BasicBinder.java:73) ~[hibernate-core-5.4.32.Final.jar:5.4.32.Final]
    at org.hibernate.type.AbstractStandardBasicType.nullSafeSet(AbstractStandardBasicType.java:276) ~[hibernate-core-5.4.32.Final.jar:5.4.32.Final]
    at org.hibernate.type.AbstractStandardBasicType.nullSafeSet(AbstractStandardBasicType.java:271) ~[hibernate-core-5.4.32.Final.jar:5.4.32.Final]
    at org.hibernate.persister.entity.AbstractEntityPersister.dehydrateId(AbstractEntityPersister.java:3040) ~[hibernate-core-5.4.32.Final.jar:5.4.32.Final]
    at org.hibernate.persister.entity.AbstractEntityPersister.dehydrate(AbstractEntityPersister.java:2998) ~[hibernate-core-5.4.32.Final.jar:5.4.32.Final]
    at org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:3289) ~[hibernate-core-5.4.32.Final.jar:5.4.32.Final]
    at org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:3825) ~[hibernate-core-5.4.32.Final.jar:5.4.32.Final]
    at org.hibernate.action.internal.EntityInsertAction.execute(EntityInsertAction.java:107) ~[hibernate-core-5.4.32.Final.jar:5.4.32.Final]
    at org.hibernate.engine.spi.ActionQueue.executeActions(ActionQueue.java:604) ~[hibernate-core-5.4.32.Final.jar:5.4.32.Final]
    at org.hibernate.engine.spi.ActionQueue.executeInserts(ActionQueue.java:461) ~[hibernate-core-5.4.32.Final.jar:5.4.32.Final]
    at org.hibernate.engine.spi.ActionQueue.addInsertAction(ActionQueue.java:258) ~[hibernate-core-5.4.32.Final.jar:5.4.32.Final]
    at org.hibernate.engine.spi.ActionQueue.addAction(ActionQueue.java:317) ~[hibernate-core-5.4.32.Final.jar:5.4.32.Final]
    at org.hibernate.event.internal.AbstractSaveEventListener.addInsertAction(AbstractSaveEventListener.java:330) ~[hibernate-core-5.4.32.Final.jar:5.4.32.Final]
    at org.hibernate.event.internal.AbstractSaveEventListener.performSaveOrReplicate(AbstractSaveEventListener.java:287) ~[hibernate-core-5.4.32.Final.jar:5.4.32.Final]
    at org.hibernate.event.internal.AbstractSaveEventListener.performSave(AbstractSaveEventListener.java:193) ~[hibernate-core-5.4.32.Final.jar:5.4.32.Final]
    at org.hibernate.event.internal.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:123) ~[hibernate-core-5.4.32.Final.jar:5.4.32.Final]
    at org.hibernate.event.internal.DefaultSaveOrUpdateEventListener.saveWithGeneratedOrRequestedId(DefaultSaveOrUpdateEventListener.java:194) ~[hibernate-core-5.4.32.Final.jar:5.4.32.Final]
    at org.hibernate.event.internal.DefaultSaveOrUpdateEventListener.entityIsTransient(DefaultSaveOrUpdateEventListener.java:179) ~[hibernate-core-5.4.32.Final.jar:5.4.32.Final]
    at org.hibernate.event.internal.DefaultSaveOrUpdateEventListener.performSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:100) ~[hibernate-core-5.4.32.Final.jar:5.4.32.Final]
    at org.hibernate.event.internal.DefaultSaveOrUpdateEventListener.onSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:75) ~[hibernate-core-5.4.32.Final.jar:5.4.32.Final]
    at org.hibernate.event.service.internal.EventListenerGroupImpl.fireEventOnEachListener(EventListenerGroupImpl.java:99) ~[hibernate-core-5.4.32.Final.jar:5.4.32.Final]
    at org.hibernate.internal.SessionImpl.fireSaveOrUpdate(SessionImpl.java:616) ~[hibernate-core-5.4.32.Final.jar:5.4.32.Final]
    at org.hibernate.internal.SessionImpl.saveOrUpdate(SessionImpl.java:609) ~[hibernate-core-5.4.32.Final.jar:5.4.32.Final]
    at org.hibernate.internal.SessionImpl.saveOrUpdate(SessionImpl.java:604) ~[hibernate-core-5.4.32.Final.jar:5.4.32.Final]
    at com.domain.api.commons.dao.impl.AdTagDAOImpl.lambda$saveOrUpdateHeaderBiddingInfo[=16=](AdTagDAOImpl.java:918) ~[open-api-commons-dao-11.0.0.jar:11.0.0]
    at java.lang.Iterable.forEach(Iterable.java:75) ~[?:?]
    at com.domain.api.commons.dao.impl.AdTagDAOImpl.saveOrUpdateHeaderBiddingInfo(AdTagDAOImpl.java:918) ~[open-api-commons-dao-11.0.0.jar:11.0.0]
    at com.domain.api.commons.processor.publisher.impl.AdTagProcessorImpl.saveOrUpdateHeaderBiddingInfo(AdTagProcessorImpl.java:2428) ~[open-api-commons-processor-11.0.0.jar:11.0.0]
    at com.domain.publisher.endpoint.AdTagServiceEndpointImpl.createAdTag(AdTagServiceEndpointImpl.java:427) ~[classes/:?]
    at com.domain.publisher.endpoint.AdTagServiceEndpointImpl$$FastClassBySpringCGLIB$fdcaf7e.invoke(<generated>) ~[classes/:?]
    at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:218) ~[spring-core-5.3.8.jar:5.3.8]
    at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:779) ~[spring-aop-5.3.8.jar:5.3.8]
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163) ~[spring-aop-5.3.8.jar:5.3.8]
    at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:750) ~[spring-aop-5.3.8.jar:5.3.8]
    at org.springframework.transaction.interceptor.TransactionInterceptor.proceedWithInvocation(TransactionInterceptor.java:123) ~[spring-tx-5.3.8.jar:5.3.8]
    at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:388) ~[spring-tx-5.3.8.jar:5.3.8]
    at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:119) ~[spring-tx-5.3.8.jar:5.3.8]
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) ~[spring-aop-5.3.8.jar:5.3.8]
    at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:750) ~[spring-aop-5.3.8.jar:5.3.8]
    at org.springframework.transaction.interceptor.TransactionInterceptor.proceedWithInvocation(TransactionInterceptor.java:123) ~[spring-tx-5.3.8.jar:5.3.8]
    at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:388) ~[spring-tx-5.3.8.jar:5.3.8]
    at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:119) ~[spring-tx-5.3.8.jar:5.3.8]
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) ~[spring-aop-5.3.8.jar:5.3.8]
    at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:750) ~[spring-aop-5.3.8.jar:5.3.8]
    at org.springframework.transaction.interceptor.TransactionInterceptor.proceedWithInvocation(TransactionInterceptor.java:123) ~[spring-tx-5.3.8.jar:5.3.8]
    at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:388) ~[spring-tx-5.3.8.jar:5.3.8]
    at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:119) ~[spring-tx-5.3.8.jar:5.3.8]
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) ~[spring-aop-5.3.8.jar:5.3.8]
    at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:750) ~[spring-aop-5.3.8.jar:5.3.8]
    at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:97) ~[spring-aop-5.3.8.jar:5.3.8]
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) ~[spring-aop-5.3.8.jar:5.3.8]
    at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:750) ~[spring-aop-5.3.8.jar:5.3.8]
    at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:692) ~[spring-aop-5.3.8.jar:5.3.8]
    at com.domain.publisher.endpoint.AdTagServiceEndpointImpl$$EnhancerBySpringCGLIB$$cca3b878.createAdTag(<generated>) ~[classes/:?]
    at jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[?:?]
    at jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[?:?]
    at jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[?:?]
    at java.lang.reflect.Method.invoke(Method.java:566) ~[?:?]
    at org.apache.cxf.service.invoker.AbstractInvoker.performInvocation(AbstractInvoker.java:180) ~[cxf-core-3.1.12.jar:3.1.12]
    :
    :
    :
    at java.lang.Thread.run(Thread.java:834) [?:?]
[WARN ][SqlExceptionHelper,qtp88259764-236] - SQL Error: 0, SQLState: S1093
[ERROR][SqlExceptionHelper,qtp88259764-236] - The index 3 is out of range.
[DEBUG][HibernateTransactionManager,qtp88259764-236] - Participating transaction failed - marking existing transaction as rollback-only

2。使用 Criteria.list() 获取任何 InStreamVideoTag subclass 实体会抛出以下错误:

org.hibernate.InstantiationException: Cannot instantiate abstract class or interface:  : com.domain.businessobject.publisher.InStreamVideoTag
    at org.hibernate.tuple.PojoInstantiator.instantiate (PojoInstantiator.java:79)
    at org.hibernate.tuple.PojoInstantiator.instantiate (PojoInstantiator.java:105)
    at org.hibernate.tuple.entity.AbstractEntityTuplizer.instantiate (AbstractEntityTuplizer.java:705)
    at org.hibernate.persister.entity.AbstractEntityPersister.instantiate (AbstractEntityPersister.java:5204)
    at org.hibernate.internal.SessionImpl.instantiate (SessionImpl.java:1598)
    at org.hibernate.internal.SessionImpl.instantiate (SessionImpl.java:1582)
    at org.hibernate.loader.Loader.instanceNotYetLoaded (Loader.java:1755)
    at org.hibernate.loader.Loader.getRow (Loader.java:1616)
    at org.hibernate.loader.Loader.getRowFromResultSet (Loader.java:740)
    at org.hibernate.loader.Loader.getRowsFromResultSet (Loader.java:1039)
    at org.hibernate.loader.Loader.processResultSet (Loader.java:990)
    at org.hibernate.loader.Loader.doQuery (Loader.java:959)
    at org.hibernate.loader.Loader.doQueryAndInitializeNonLazyCollections (Loader.java:349)
    at org.hibernate.loader.Loader.doList (Loader.java:2843)
    at org.hibernate.loader.Loader.doList (Loader.java:2825)
    at org.hibernate.loader.Loader.listIgnoreQueryCache (Loader.java:2657)
    at org.hibernate.loader.Loader.list (Loader.java:2652)
    at org.hibernate.loader.criteria.CriteriaLoader.list (CriteriaLoader.java:109)
    at org.hibernate.internal.SessionImpl.list (SessionImpl.java:1877)
    at org.hibernate.internal.CriteriaImpl.list (CriteriaImpl.java:370)
    at com.domain.api.commons.dao.impl.AdTagDAOImpl.getVideoTagsByAdTagGrp (AdTagDAOImpl.java:1002)
    at com.domain.api.commons.processor.publisher.impl.AdTagProcessorImpl.getVideoTagsByAdTagGrp (AdTagProcessorImpl.java:2423)
    at com.domain.publisher.endpoint.AdTagServiceEndpointImpl.getAdTagGroup (AdTagServiceEndpointImpl.java:72)
    at com.domain.publisher.endpoint.AdTagServiceEndpointImpl.searchAdTags (AdTagServiceEndpointImpl.java:1341)
    at com.domain.publisher.endpoint.AdTagServiceEndpointImpl$$FastClassBySpringCGLIB$fdcaf7e.invoke (<generated>)

注意: 尝试将抽象 InStreamVideoTag 更改为具体 class。它消除了错误,但实际上并没有从数据库加载 RegularInStreamVideoTag 类型的对象,它仅加载 InStreamVideoTag 对象。

感谢阅读!

最后,在删除所有 类 上的所有 @DiscriminatorColumn@DiscriminatorValue 注释后,问题得到解决。看起来 hibernate 5 对注释很严格。现在,生成的用于检索记录的连接查询类似于 Hibernate 4。它使用名为 clazz 的特殊列使用 case 语句来确定继承类型。此列将由 hibernate 内部使用。