I have the same problem as you have with generated single valued
@EmbeddedId entity identifiers.
I'm using TableGenerator and only
javax.persistence annotations to declare identifier generators.
Here is a simplified example of my problem. This example works with OpenJPA 0.9.6 implementation, but not with Hibernate 3.2.1.ga.
Hibernate does not use the defined TableGenerator and tries to insert NULL into Entity_Id database field. (Null value probably from the
id = new Id() definition in SimpleEntity class)
Any help is appreciated.
Database tables (Oracle specific):
Code:
CREATE TABLE Id_Generators (
Gen_Key VARCHAR2(60) NOT NULL,
Gen_Value NUMBER(19) NOT NULL,
PRIMARY KEY (Gen_Key)
);
CREATE TABLE Simple_Entity (
Entity_Id NUMBER(19) NOT NULL,
Entity_Text VARCHAR2(126) NOT NULL,
PRIMARY KEY (Entity_Id)
);
Entity and Identity classes:Code:
import java.io.Serializable;
public interface Identifiable extends Serializable{
public Id getId();
}
Code:
import java.io.Serializable;
import javax.persistence.Column;
import javax.persistence.Embeddable;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.TableGenerator;
@Embeddable
public class Id implements Serializable{
@TableGenerator(name="ID_GEN", table="ID_GENERATORS",
pkColumnName="GEN_KEY", valueColumnName="GEN_VALUE",
pkColumnValue="ID", allocationSize=30)
@GeneratedValue(strategy=GenerationType.TABLE, generator="ID_GEN")
@Column(name = "ID")
private Long value;
public Id() { }
public Long getValue() { return value; }
public void setValue(Long value) { this.value = value; }
public int hashCode () {
return ((this.value == null) ? 0 : this.value.hashCode ());
}
public boolean equals (Object obj) {
if (this == obj) {
return true;
}
if (obj == null || obj.getClass() != this.getClass()) {
return false;
}
Id other = (Id) obj;
return ((value == null && other.getValue() == null)
|| (value != null && value.equals (other.getValue())));
}
}
Code:
import javax.persistence.AttributeOverride;
import javax.persistence.Column;
import javax.persistence.EmbeddedId;
import javax.persistence.Entity;
import javax.persistence.Table;
@Entity
@Table(name ="SIMPLE_ENTITY")
public class SimpleEntity implements Identifiable {
@EmbeddedId
@AttributeOverride(name="value", column=@Column(name = "ENTITY_ID"))
private Id id = new Id();
@Column(name="ENTITY_TEXT", nullable=false)
private String text;
public SimpleEntity() {}
public SimpleEntity(String text) {this.text = text;}
public Id getId() { return id; }
public String getEntityValue() {return text; }
public void setEntityValue(String text) { this.text = text; }
}
Code:
// Spring Framework in use, details omitted
public void testSimpleEntity() {
SimpleEntity e = new SimpleEntity("Hello");
basicService.save(e);
}
Exception Log messageCode:
DEBUG jdbc.AbstractBatcher:393 [log] (2007-01-13 10:23:25,500)
insert
into
SIMPLE_ENTITY
(ENTITY_TEXT, ENTITY_ID)
values
(?, ?)
WARN util.JDBCExceptionReporter:77 [logExceptions] (2007-01-13 10:23:25,578) SQL Error: 1400, SQLState: 23000
ERROR util.JDBCExceptionReporter:78 [logExceptions] (2007-01-13 10:23:25,578) ORA-01400: cannot insert NULL into ("JULIA_TEST"."SIMPLE_ENTITY"."ENTITY_ID")
WARN util.JDBCExceptionReporter:77 [logExceptions] (2007-01-13 10:23:25,578) SQL Error: 1400, SQLState: 23000
ERROR util.JDBCExceptionReporter:78 [logExceptions] (2007-01-13 10:23:25,593) ORA-01400: cannot insert NULL into ("JULIA_TEST"."SIMPLE_ENTITY"."ENTITY_ID")
ERROR def.AbstractFlushingEventListener:301 [performExecutions] (2007-01-13 10:23:25,593) Could not synchronize database state with session
org.hibernate.exception.ConstraintViolationException: Could not execute JDBC batch update
at org.hibernate.exception.SQLStateConverter.convert(SQLStateConverter.java:71)
at org.hibernate.exception.JDBCExceptionHelper.convert(JDBCExceptionHelper.java:43)
at org.hibernate.jdbc.AbstractBatcher.executeBatch(AbstractBatcher.java:249)
at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:235)
at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:139)
at org.hibernate.event.def.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:298)
at org.hibernate.event.def.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:27)
at org.hibernate.impl.SessionImpl.flush(SessionImpl.java:1000)
at org.hibernate.impl.SessionImpl.managedFlush(SessionImpl.java:338)
at org.hibernate.transaction.JDBCTransaction.commit(JDBCTransaction.java:106)
at org.hibernate.ejb.TransactionImpl.commit(TransactionImpl.java:54)
at org.springframework.orm.jpa.JpaTransactionManager.doCommit(JpaTransactionManager.java:419)
at org.springframework.transaction.support.AbstractPlatformTransactionManager.processCommit(AbstractPlatformTransactionManager.java:611)
at org.springframework.transaction.support.AbstractPlatformTransactionManager.commit(AbstractPlatformTransactionManager.java:581)
at org.springframework.transaction.interceptor.TransactionAspectSupport.commitTransactionAfterReturning(TransactionAspectSupport.java:307)
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:117)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:176)
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:210)
at $Proxy19.save(Unknown Source)
at BasicServiceSaveTest.testSimpleEntity(BasicServiceSaveTest.java:136)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at junit.framework.TestCase.runTest(TestCase.java:154)
at junit.framework.TestCase.runBare(TestCase.java:127)
at junit.framework.TestResult$1.protect(TestResult.java:106)
at junit.framework.TestResult.runProtected(TestResult.java:124)
at junit.framework.TestResult.run(TestResult.java:109)
at junit.framework.TestCase.run(TestCase.java:118)
at junit.framework.TestSuite.runTest(TestSuite.java:208)
at junit.framework.TestSuite.run(TestSuite.java:203)
at junit.extensions.TestDecorator.basicRun(TestDecorator.java:22)
at junit.extensions.TestSetup$1.protect(TestSetup.java:19)
at junit.framework.TestResult.runProtected(TestResult.java:124)
at junit.extensions.TestSetup.run(TestSetup.java:23)
at org.eclipse.jdt.internal.junit.runner.junit3.JUnit3TestReference.run(JUnit3TestReference.java:128)
at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:460)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:673)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:386)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:196)
Caused by: java.sql.BatchUpdateException: ORA-01400: cannot insert NULL into ("JULIA_TEST"."SIMPLE_ENTITY"."ENTITY_ID")
at oracle.jdbc.driver.DatabaseError.throwBatchUpdateException(DatabaseError.java:343)
at oracle.jdbc.driver.OraclePreparedStatement.executeBatch(OraclePreparedStatement.java:10656)
at com.mchange.v2.c3p0.impl.NewProxyPreparedStatement.executeBatch(NewProxyPreparedStatement.java:1723)
at org.hibernate.jdbc.BatchingBatcher.doExecuteBatch(BatchingBatcher.java:48)
at org.hibernate.jdbc.AbstractBatcher.executeBatch(AbstractBatcher.java:242)
... 39 more