Hello,
im relative new to hibernate and constantly running into a problem for severall hours now. I hope you can help.
Im building up a new web applikation and started developing my domain model. I need to persist two implementing classes of an interface:
Code:
public interface IInsurance {
public Integer getId();
public void setId(Integer id);
public String getName();
public void setName(String name);
public Set<IPatient> getPatients();
public void setPatients(Set<IPatient> patients);
public void addPatient(IPatient patient);
}
Code:
public class HealthInsuranceImpl implements IInsurance {
private Integer id;
private String name;
private Set<IPatient> patients = new HashSet<IPatient>();
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Set<IPatient> getPatients() {
return patients;
}
public void setPatients(Set<IPatient> patients) {
this.patients = patients;
}
public void addPatient(IPatient patient) {
patient.setInsurance(this);
if (patients == null) {
patients = new HashSet<IPatient>();
}
patients.add(patient);
}
}
Code:
public class CareInsuranceImpl implements IInsurance {
private Integer id;
private String name;
private Set<IPatient> patients = new HashSet<IPatient>();
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Set<IPatient> getPatients() {
return patients;
}
public void setPatients(Set<IPatient> patients) {
this.patients = patients;
}
public void addPatient(IPatient patient) {
patient.setInsurance(this);
if (patients == null) {
patients = new HashSet<IPatient>();
}
patients.add(patient);
}
}
on the otherhand i got a class Patient. So one insurance can have many patients:
Code:
public class PatientImpl implements IPatient {
// persistant fields
private Integer id;
private String firstName;
private String lastName;
private PatientStateEnum state;
private Date dateOfBirth;
private IInsurance insurance;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
.
.
.
public IInsurance getInsurance() {
return insurance;
}
public void setInsurance(IInsurance insurance) {
this.insurance = insurance;
}
}
this is the mapping file for the Patient class:
Code:
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="PatientImpl"
table="patient">
<id name="id" type="java.lang.Integer">
<column name="id" />
<generator class="native" />
</id>
<many-to-one name="insurance" column="insurance_fk"
class="IInsurance" cascade="save-update"/>
</class>
</hibernate-mapping>
Im trying to map the interface using the one table per concrete subclass strategy. This is the mapping file for the interface (and the subclasses)
Code:
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="IInsurance"
abstract="true">
<id name="id" type="java.lang.Integer">
<column name="id" />
<generator class="native" />
</id>
<union-subclass
name="HealthInsuranceImpl"
table="insurance_health">
<property name="name" column="name" length="255" not-null="true" />
<set name="patients" inverse="false" cascade="save-update">
<key column="insurance_fk" />
<one-to-many
class="PatientImpl" />
</set>
</union-subclass>
<!--
<union-subclass
name="CareInsuranceImpl"
table="insurance_care">
<property name="name" column="name" length="255" not-null="true" />
<set name="patients" inverse="false" cascade="save-update">
<key column="insurance_fk" />
<one-to-many
class="PatientImpl" />
</set>
</union-subclass>
-->
</class>
</hibernate-mapping>
notice that the subclass "CareInsuranceImpl" is commented out. so only one subclass of the interface is actually mapped. Running my Unittest with this configuration works. My objects get written into the database correctly.
Here comes the problem in. As soon as i comment the second subclass in (and thus map it) my test code fails. I get following error:
Quote:
INFO - Hibernate 3.2.6
INFO - hibernate.properties not found
INFO - Bytecode provider name : cglib
INFO - using JDK 1.4 java.sql.Timestamp handling
INFO - configuring from file: hibernate.cfg.xml
INFO - Reading mappings from resource : hibernate-mapping/PatientImpl.hbm.xml
INFO - Mapping class: quelltextschmiede.papp.papp3.domain.patient.PatientImpl -> patient
INFO - Reading mappings from resource : hibernate-mapping/IInsurance.hbm.xml
INFO - Mapping class: quelltextschmiede.papp.papp3.domain.insurance.IInsurance -> IInsurance
INFO - Mapping union-subclass: quelltextschmiede.papp.papp3.domain.insurance.HealthInsuranceImpl -> insurance_health
INFO - Mapping union-subclass: quelltextschmiede.papp.papp3.domain.insurance.CareInsuranceImpl -> insurance_care
INFO - Configured SessionFactory: null
INFO - Mapping collection: quelltextschmiede.papp.papp3.domain.insurance.HealthInsuranceImpl.patients -> patient
INFO - Mapping collection: quelltextschmiede.papp.papp3.domain.insurance.CareInsuranceImpl.patients -> patient
INFO - Using Hibernate built-in connection pool (not for production use!)
INFO - Hibernate connection pool size: 20
INFO - autocommit mode: false
INFO - using driver: oracle.jdbc.OracleDriver at URL: jdbc:oracle:thin:@localhost:1521:XE
INFO - connection properties: {user=papp, password=****}
INFO - RDBMS: Oracle, version: Oracle Database 10g Express Edition Release 10.2.0.1.0 - Production
INFO - JDBC driver: Oracle JDBC driver, version: 10.2.0.1.0XE
INFO - Using dialect: org.hibernate.dialect.Oracle10gDialect
INFO - Using default transaction strategy (direct JDBC transactions)
INFO - No TransactionManagerLookup configured (in JTA environment, use of read-write or transactional second-level cache is not recommended)
INFO - Automatic flush during beforeCompletion(): disabled
INFO - Automatic session close at end of transaction: disabled
INFO - JDBC batch size: 15
INFO - JDBC batch updates for versioned data: disabled
INFO - Scrollable result sets: enabled
INFO - JDBC3 getGeneratedKeys(): disabled
INFO - Connection release mode: auto
INFO - Default batch fetch size: 1
INFO - Generate SQL with comments: disabled
INFO - Order SQL updates by primary key: disabled
INFO - Order SQL inserts for batching: disabled
INFO - Query translator: org.hibernate.hql.ast.ASTQueryTranslatorFactory
INFO - Using ASTQueryTranslatorFactory
INFO - Query language substitutions: {}
INFO - JPA-QL strict compliance: disabled
INFO - Second-level cache: enabled
INFO - Query cache: disabled
INFO - Cache provider: org.hibernate.cache.NoCacheProvider
INFO - Optimize cache for minimal puts: disabled
INFO - Structured second-level cache entries: disabled
INFO - Echoing all SQL to stdout
INFO - Statistics: disabled
INFO - Deleted entity synthetic identifier rollback: disabled
INFO - Default entity-mode: pojo
INFO - Named query checking : enabled
INFO - building session factory
INFO - Not binding factory to JNDI, no JNDI name configured
INFO - Running hbm2ddl schema export
INFO - exporting generated schema to database
INFO - schema export complete
Hibernate:
select
hibernate_sequence.nextval
from
dual
Hibernate:
select
hibernate_sequence.nextval
from
dual
Hibernate:
insert
into
insurance_health
(name, id)
values
(?, ?)
Hibernate:
insert
into
patient
(first_name, last_name, state, date_of_birth, insurance_fk, id)
values
(?, ?, ?, ?, ?, ?)
WARN - SQL Error: 2291, SQLState: 23000
ERROR - ORA-02291: Integritäts-Constraint (PAPP.FKD0D3EB05BABC3590) verletzt - übergeordneter Schlüssel nicht gefunden
WARN - SQL Error: 2291, SQLState: 23000
ERROR - ORA-02291: Integritäts-Constraint (PAPP.FKD0D3EB05BABC3590) verletzt - übergeordneter Schlüssel nicht gefunden
ERROR - 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:253)
at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:266)
at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:167)
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 quelltextschmiede.papp.papp3.domain.patient.SaveTest.testSave(SaveTest.java:64)
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:168)
at junit.framework.TestCase.runBare(TestCase.java:134)
at junit.framework.TestResult$1.protect(TestResult.java:110)
at junit.framework.TestResult.runProtected(TestResult.java:128)
at junit.framework.TestResult.run(TestResult.java:113)
at junit.framework.TestCase.run(TestCase.java:124)
at junit.framework.TestSuite.runTest(TestSuite.java:232)
at junit.framework.TestSuite.run(TestSuite.java:227)
at org.junit.internal.runners.JUnit38ClassRunner.run(JUnit38ClassRunner.java:79)
at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:45)
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-02291: Integritäts-Constraint (PAPP.FKD0D3EB05BABC3590) verletzt - übergeordneter Schlüssel nicht gefunden
at oracle.jdbc.driver.DatabaseError.throwBatchUpdateException(DatabaseError.java:498)
at oracle.jdbc.driver.OraclePreparedStatement.executeBatch(OraclePreparedStatement.java:12369)
at org.hibernate.jdbc.BatchingBatcher.doExecuteBatch(BatchingBatcher.java:48)
at org.hibernate.jdbc.AbstractBatcher.executeBatch(AbstractBatcher.java:246)
... 25 more
INFO - closing
INFO - cleaning up connection pool: jdbc:oracle:thin:@localhost:1521:XE
[/code]
Here is my testcode:
Code:
public void testSave() {
Session session = sessionFactory.openSession();
IInsurance insurance = new HealthInsuranceImpl();
insurance.setName("BLA");
PatientImpl patient = new PatientImpl();
patient.setFirstName("Hans");
patient.setLastName("Müller3");
patient.setState(PatientStateEnum.ACTIVE);
patient.setDateOfBirth(new Date());
insurance.addPatient(patient);
session.saveOrUpdate(insurance);
session.flush();
session.close();
}
[/code]
this is very strange, because everything works fine if i just have one subclass of the interface mapped. As soon i have the second subclass mapped, i get this error. Please help :(
P.S.: im using Oracle Database 10g Express Edition