Hi,
I am working with Hibernate 3.1.1 on PostgreSQL 8.1.0 and I have a very basic problem with a parent/child relationship and deletes.
I have a Parent object called Layout, with a simple one-to-one relationship to a child object called Cell. What I want, is that when I delete the parent object, Layout, the child object Cell is deleted too.
I am using many-to-one mapping and not one-to-one mapping. The simplified code of the two classes is as follows:
Parent class:
Code:
public class Layout {
private Cell cell;
public void setCell(Cell cell) {
this.cell = cell;
}
public Cell getCell() {
return this.cell;
}
}
Child class:
Code:
public class Cell {
private Layout layout;
public void setLayout(Layout layout) {
this.layout = layout;
}
public Layout getLayout() {
return this.layout;
}
}
When a Layout is created, here's what happens:
Code:
Layout l = new Layout();
l.setCell(new Cell());
l.getCell().setLayout(l);
As you can see, there is a two-directional relationship between the two objects. The two objects are mapped as follows (only the relevant part is here):
Code:
<class name="my.company.layout.Layout" table="CELL" lazy="false">
<!-- id and other fields are here and work perfectly -->
<many-to-one name="cell" class="my.company.cell.Cell"
cascade="all" lazy="false">
<column name="CELL_ID" sql-type="NUMERIC(18,0)" unique="true" />
</many-to-one>
</class>
Code:
<class name="my.company.cell.Cell" table="CELL" lazy="false">
<!-- id and other fields are here and work perfectly -->
<many-to-one name="layout"
class="my.company.layout.Layout" cascade="all">
<column name="LAYOUT_ID" sql-type="NUMERIC(18,0)" unique="true" not-null="false" />
</many-to-one>
</class>
When I try to delete a Layout, here's what I do:
Code:
Transaction tx = getHibernateSession().createTransaction();
getHibernateSession().createQuery("DELETE FROM Layout WHERE ID=" + id").executeUpdate();
tx.commit();
The generated SQL and error is as follows:
Code:
Hibernate: insert into HT_LAYOUT select bulk_target.PID as PID from LAYOUT bulk_target inner join PRODUCT bulk_target_1_ on bulk_target.PID=bulk_target_1_.ID where PID=185
Hibernate: delete from LAYOUT_SPOOL where (PID) IN (select PID from HT_LAYOUT)
Hibernate: delete from LAYOUT_SHEET where (PID) IN (select PID from HT_LAYOUT)
Hibernate: delete from LAYOUT where (PID) IN (select PID from HT_LAYOUT)
WARN - SQL Error: 0, SQLState: 23503
ERROR - ERROR: update or delete on "layout" violates foreign key constraint "fk1f8162dfc85e53" on "cell"
Dettaglio: Key (pid)=(185) is still referenced from table "cell".
WARN - unable to drop temporary id table after use
org.postgresql.util.PSQLException: ERROR: current transaction is aborted, commands ignored until end of transaction block
[...]
ERROR - org.hibernate.exception.ConstraintViolationException: error performing bulk delete
[...]
Caused by: org.postgresql.util.PSQLException: ERROR: update or delete on "layout" violates foreign key constraint "fk1f8162dfc85e53" on "cell"
Dettaglio: Key (pid)=(185) is still referenced from table "cell".
The multiple deletes are due to the fact that Layout is really a joined subclass but this is not the point here.
Hibernate is trying to delete the parent table first, when it should delete the child table first. Of course, this causes a foreign key constraint failure because the child table still contains a reference to the parent table and the delete cannot be performed.
What am I doing wrong and why is this happening?
Please note that in my first implementation, only the parent had a reference to the child, so upon deleting the parent, the parent would get deleted but the child would not be deleted, resulting in the database being filled with orphan children.
Thanks in advance for your time.