|
Joined inheritence is completely broken in all versions of hibernate > 4.2.8. If I switch to singletable it seems to work but that was not a viable option for my testing so I had to downgrade hibernate. While doing debugging, I noticed the SQL queries produced by entityManager.persist() against the child table contain 1 fewer "?" than the number of fields in the child+parent table with 1 field for the discriminator set as a static (non-replaceable) parameter in the prepared statement.
so if my parent table has 3 columns (id, version, account_type) and the child table has 1 column (name_on_card) then the sql produced is insert into parent_tab1(id, version, account_type) values (?, ?, 'CHILDDESCRIMINATOR',?)
The commit throws an error similar to Caused by: org.h2.jdbc.JdbcSQLException: Invalid value "4" for parameter "parameterIndex" [90008-181]
you can verify this all with the test code below (heavily redacted to protect IP).
This issue is not Database/Dialect specific as I produce it on SQLServer2012 and H2. additional notes, I am using spring to bootstrap my app and my tests but can produce it with just an entityManager.
Also If I switch from 4.3.x to 4.2.8.FINAL, the problem goes away. The problem is produced and exists with 4.2.16, 4.3.7 and 4.3.2. It likely occurs with all versions after 4.2.8 but I didn't test with all of them.
Sample Parent Entity: ``` @Entity @Table(name="payment_account", uniqueConstraints= { @UniqueConstraint(columnNames= {"company_id", "company_account_id"}
)} ) @Inheritance(strategy=InheritanceType.JOINED) @DiscriminatorColumn(name="account_type", discriminatorType=DiscriminatorType.STRING) @DiscriminatorValue("") public abstract class PaymentAccount implements Serializable { abstract public void initPaymentAccountName() ; @Id @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "payment_account_seq") @SequenceGenerator(name = "payment_account_seq", sequenceName = "payment_account_seq", initialValue = 1, allocationSize = 1) @Column(name = "id") private Long id; @Version @Column(name = "version") private Integer version; @Column(name="account_type") @Enumerated(EnumType.STRING) private AccountType accountType; @ManyToOne(fetch = FetchType.LAZY, targetEntity = Company.class) @JoinColumn(name = "company_id", referencedColumnName = "id") private Company company; @Column(name="company_account_id") private String companyAccountId; private String accountHolderName; // getters and setters removed for brevity }
```
Child entity: ```
@Entity @DiscriminatorValue("CREDITCARD") @Table(name="credit_card_account") public class CreditCardAccount extends PaymentAccount implements Serializable { private String nameOnCard; // getters and setters again removed for brevity }
```
Here is an exception example: org.springframework.orm.jpa.JpaSystemException: could not insert: [entity.CreditCardAccount]; nested exception is org.hibernate.exception.GenericJDBCException: could not insert: [entity.CreditCardAccount] at org.springframework.orm.jpa.vendor.HibernateJpaDialect.convertHibernateAccessException(HibernateJpaDialect.java:303) at org.springframework.orm.jpa.vendor.HibernateJpaDialect.translateExceptionIfPossible(HibernateJpaDialect.java:214) at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.translateExceptionIfPossible(AbstractEntityManagerFactoryBean.java:417) at org.springframework.dao.support.ChainedPersistenceExceptionTranslator.translateExceptionIfPossible(ChainedPersistenceExceptionTranslator.java:59) at org.springframework.dao.support.DataAccessUtils.translateIfNecessary(DataAccessUtils.java:213) at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:147) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) at org.springframework.data.jpa.repository.support.CrudMethodMetadataPostProcessor$CrudMethodMetadataPopulatingMethodIntercceptor.invoke(CrudMethodMetadataPostProcessor.java:122) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:92) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:207) at repository.PaymentAccountRepositoryTest.saveIt(PaymentAccountRepositoryTest.java:174) at repository.PaymentAccountRepositoryTest.testSave(PaymentAccountRepositoryTest.java:158) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at java.lang.reflect.Method.invoke(Method.java:606) at org.springframework.test.context.junit4.statements.RunBeforeTestMethodCallbacks.evaluate(RunBeforeTestMethodCallbacks.java:72) at org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks.evaluate(RunAfterTestMethodCallbacks.java:81) at org.springframework.test.context.junit4.statements.SpringRepeat.evaluate(SpringRepeat.java:72) at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:216) at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:82) at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:60) at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:67) at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:162) at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:50) at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:459) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:675) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:382) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:192) Caused by: org.hibernate.exception.GenericJDBCException: could not insert: [entity.CreditCardAccount] at org.hibernate.exception.internal.StandardSQLExceptionConverter.convert(StandardSQLExceptionConverter.java:54) at org.hibernate.engine.jdbc.spi.SqlExceptionHelper.convert(SqlExceptionHelper.java:126) at org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:3144) at org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:3581) at org.hibernate.action.internal.EntityInsertAction.execute(EntityInsertAction.java:104) at org.hibernate.engine.spi.ActionQueue.executeActions(ActionQueue.java:463) at org.hibernate.engine.spi.ActionQueue.executeActions(ActionQueue.java:349) at org.hibernate.event.internal.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:350) at org.hibernate.event.internal.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:56) at org.hibernate.internal.SessionImpl.flush(SessionImpl.java:1222) at org.hibernate.jpa.spi.AbstractEntityManagerImpl.flush(AbstractEntityManagerImpl.java:1335) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at java.lang.reflect.Method.invoke(Method.java:606) at org.springframework.orm.jpa.SharedEntityManagerCreator$SharedEntityManagerInvocationHandler.invoke(SharedEntityManagerCreator.java:289) at org.springframework.data.jpa.repository.support.SimpleJpaRepository.flush(SimpleJpaRepository.java:441) at org.springframework.data.jpa.repository.support.SimpleJpaRepository.saveAndFlush(SimpleJpaRepository.java:409) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at java.lang.reflect.Method.invoke(Method.java:606) at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.executeMethodOn(RepositoryFactorySupport.java:442) at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.doInvoke(RepositoryFactorySupport.java:427) at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.invoke(RepositoryFactorySupport.java:381) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) at org.springframework.transaction.interceptor.TransactionInterceptor$1.proceedWithInvocation(TransactionInterceptor.java:98) at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:266) at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:95) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:136) ... 24 more Caused by: org.h2.jdbc.JdbcSQLException: Invalid value "15" for parameter "parameterIndex" [90008-181] at org.h2.message.DbException.getJdbcSQLException(DbException.java:345) at org.h2.message.DbException.get(DbException.java:179) at org.h2.message.DbException.getInvalidValueException(DbException.java:228) at org.h2.jdbc.JdbcPreparedStatement.setParameter(JdbcPreparedStatement.java:1382) at org.h2.jdbc.JdbcPreparedStatement.setLong(JdbcPreparedStatement.java:591) at org.apache.tomcat.dbcp.dbcp.DelegatingPreparedStatement.setLong(DelegatingPreparedStatement.java:123) at org.apache.tomcat.dbcp.dbcp.DelegatingPreparedStatement.setLong(DelegatingPreparedStatement.java:123) at org.hibernate.type.descriptor.sql.BigIntTypeDescriptor$1.doBind(BigIntTypeDescriptor.java:64) at org.hibernate.type.descriptor.sql.BasicBinder.bind(BasicBinder.java:90) at org.hibernate.type.AbstractStandardBasicType.nullSafeSet(AbstractStandardBasicType.java:286) at org.hibernate.type.AbstractStandardBasicType.nullSafeSet(AbstractStandardBasicType.java:281) at org.hibernate.persister.entity.AbstractEntityPersister.dehydrateId(AbstractEntityPersister.java:2880) at org.hibernate.persister.entity.AbstractEntityPersister.dehydrate(AbstractEntityPersister.java:2849) at org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:3121) ... 48 more
|