Hi,
I'm working on a small application to get to know hibernate. To the point I have implementet a domain model that looks like this:

I used the table per class strategy and my Person.hbm.xml looks like this:
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 package="de.ritter.orm.model">
<class name="de.ritter.orm.model.impl.PersonImpl" table="PERSON">
<id name="id" column="ID">
<generator class="native"/>
</id>
<property name="birthday" type="timestamp" column="BIRTHDAY"/>
<property name="firstName" column="FIRST_NAME"/>
<property name="lastName" column="LAST_NAME"/>
<component name="address" class="de.ritter.orm.model.impl.AddressImpl">
<property name="street" column="ADDRESS_STREET"/>
<property name="city" column="ADDRESS_CITY"/>
<property name="state" column="ADDRESS_STATE"/>
<property name="zip" column="ADDRESS_ZIP"/>
</component>
<joined-subclass abstract="true"
name="de.ritter.orm.model.impl.AbstractEmployeeImpl"
table="EMPLOYEE">
<key column="ID" />
<property name="hireDate" type="timestamp" column="HIRE_DATE"/>
<many-to-one name="superior"
column="SUPERIOR_ID"
entity-name="FullTimeEmployee"/>
<joined-subclass name="de.ritter.orm.model.impl.FullTimeEmployeeImpl"
table="FULL_TIME_EMPLOYEE">
<key column="ID" />
<property name="salary" type="double" />
</joined-subclass>
<joined-subclass name="de.ritter.orm.model.impl.PartTimeEmployeeImpl"
table="PART_TIME_EMPLOYEE">
<key column="ID" />
<property name="hourlyWage" type="double" column="HOURLY_WAGE" />
</joined-subclass>
</joined-subclass>
</class>
</hibernate-mapping>
To get this example to work I had to map FullTimeEmployee twice. The FullTimeEomployee.hbm.xml looks like this:
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 package="de.ritter.orm.model">
<class name="de.ritter.orm.model.impl.FullTimeEmployeeImpl"
table="FULL_TIME_EMPLOYEE"
entity-name="FullTimeEmployee">
<id name="id" column="id">
<generator class="native"/>
</id>
<property name="salary" type="double" />
</class>
</hibernate-mapping>
That all looks pretty straight forward to me. Inserting new FullTimeEmployees using the following code works fine and everything gets set up correctly
Code:
public void saveEmployee(IEmployee employee) {
getSession().beginTransaction();
getSession().save(employee);
getSession().getTransaction().commit();
}
However, when I try to delete a FullTimeEmployee I'm getting a StaleObjectStateException (actually I inserted the employee first to delete him directly again, that is where the insert statements come from):
Code:
SLF4J: Failed to load class "org.slf4j.impl.StaticLoggerBinder".
SLF4J: Defaulting to no-operation (NOP) logger implementation
SLF4J: See http://www.slf4j.org/codes.html#StaticLoggerBinder for further details.
Hibernate: insert into PERSON (BIRTHDAY, FIRST_NAME, LAST_NAME, ADDRESS_STREET, ADDRESS_CITY, ADDRESS_STATE, ADDRESS_ZIP) values (?, ?, ?, ?, ?, ?, ?)
Hibernate: insert into EMPLOYEE (HIRE_DATE, SUPERIOR_ID, ID) values (?, ?, ?)
Hibernate: insert into FULL_TIME_EMPLOYEE (salary, ID) values (?, ?)
Hibernate: select this_.id as id2_0_, this_.salary as salary2_0_ from FULL_TIME_EMPLOYEE this_
Hibernate: select this_.ID as ID0_0_, this_1_.BIRTHDAY as BIRTHDAY0_0_, this_1_.FIRST_NAME as FIRST3_0_0_, this_1_.LAST_NAME as LAST4_0_0_, this_1_.ADDRESS_STREET as ADDRESS5_0_0_, this_1_.ADDRESS_CITY as ADDRESS6_0_0_, this_1_.ADDRESS_STATE as ADDRESS7_0_0_, this_1_.ADDRESS_ZIP as ADDRESS8_0_0_, this_.HIRE_DATE as HIRE2_1_0_, this_.SUPERIOR_ID as SUPERIOR3_1_0_, this_2_.salary as salary2_0_, this_3_.HOURLY_WAGE as HOURLY2_3_0_, case when this_2_.id is not null then 2 when this_3_.ID is not null then 3 when this_.ID is not null then 1 end as clazz_0_ from EMPLOYEE this_ inner join PERSON this_1_ on this_.ID=this_1_.ID left outer join FULL_TIME_EMPLOYEE this_2_ on this_.ID=this_2_.id left outer join PART_TIME_EMPLOYEE this_3_ on this_.ID=this_3_.ID
Hibernate: delete from FULL_TIME_EMPLOYEE where ID=?
Hibernate: delete from EMPLOYEE where ID=?
Hibernate: delete from PERSON where ID=?
Hibernate: delete from FULL_TIME_EMPLOYEE where ID=?
Exception in thread "main" org.hibernate.StaleObjectStateException: Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect): [de.ritter.orm.model.impl.FullTimeEmployeeImpl#1]
at org.hibernate.persister.entity.AbstractEntityPersister.check(AbstractEntityPersister.java:1950)
at org.hibernate.persister.entity.AbstractEntityPersister.delete(AbstractEntityPersister.java:2710)
at org.hibernate.persister.entity.AbstractEntityPersister.delete(AbstractEntityPersister.java:2911)
at org.hibernate.action.EntityDeleteAction.execute(EntityDeleteAction.java:97)
at org.hibernate.engine.ActionQueue.execute(ActionQueue.java:273)
at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:265)
at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:189)
at org.hibernate.event.def.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:321)
at org.hibernate.event.def.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:51)
at org.hibernate.impl.SessionImpl.flush(SessionImpl.java:1216)
at org.hibernate.impl.SessionImpl.managedFlush(SessionImpl.java:383)
at org.hibernate.transaction.JDBCTransaction.commit(JDBCTransaction.java:133)
at de.ritter.orm.services.impl.EmployeeServiceImpl.deleteEmployee(EmployeeServiceImpl.java:44)
at de.ritter.orm.HibernateTest.delete(HibernateTest.java:35)
at de.ritter.orm.HibernateTest.main(HibernateTest.java:25)
Obviously what is happening is, that Hibernate tries to delete a FullTimeEmployee twice. The first time ist for the class/subclass relationship and the second time is for the superior reference.
I tried a lot of attributes on the many-to-one relationship without really knowing what I was doing (like not-null=false, update=-false, optimistic-lock=false etc.), but nothing works.
There seems to be something wrong with the mapping, because without the many to one relationship everything works fine.
If anyone knows what I'm doing wrong, feel free to answer :)
Regards
Benedikt