We have a Customer, Order and CreditCard. The mapping for these entities are below.
1. A CreditCard is always associated with a Customer.
2. An Order is always associated with a Customer.
The problem:
When we delete a Customer this cascades the delete to CreditCards and Orders the way we want to , but Orders should be deleted first and then CreditCards. This is because Orders need to have CreditCards.
Is there a way in Hibernate to control the order of cascading deletes? Or is there an alternative that we can use to achieve the same effect?
Thanks.
Hibernate version: 3.0
Mapping documents:
Code:
<class name="Order" table="`order`">
<id name="id" unsaved-value="0">
<generator class="native"/>
</id>
<version name="version" type="long" unsaved-value="null"/>
<many-to-one name="creditCard" column="creditCardId" lazy="true" class="CreditCard" not-null="true"/>
<many-to-one name="customer" column="customerId" lazy="true" class="Customer" not-null="true"/>
<set name="orderItems" access="field" lazy="true" cascade="all">
<key column="orderId" not-null="true"/>
<one-to-many class="OrderItem"/>
</set>
<set name="destinations" access="field" lazy="true" cascade="all">
<key column="orderId" not-null="true"/>
<one-to-many class="Destination"/>
</set>
</class>
Code:
<class name="Customer" table="customer">
<id name="id" unsaved-value="0">
<generator class="native"/>
</id>
<version name="version" type="long" unsaved-value="null"/>
<property name="emailAddress" type="string" unique="true"/>
<property name="password" type="string"/>
<component name="nameComponent">
<property name="first" type="string"/>
<property name="last" type="string"/>
<property name="company" type="string"/>
</component>
<one-to-one name="cart" class="Cart" cascade="all" lazy="true"/>
<set name="contacts" access="field" lazy="true" cascade="all">
<key column="entityId" foreign-key="none"/>
<one-to-many class="Contact"/>
</set>
<set name="orders" lazy="true" cascade="all" >
<key column="customerId"/>
<one-to-many class="Order"/>
</set>
<set name="creditCards" lazy="true" cascade="all-delete-orphan">
<key column="customerId"/>
<one-to-many class="CreditCard"/>
</set>
</class>
Code:
<class name="CreditCard" table="creditcard">
<id name="id" unsaved-value="0">
<generator class="native"/>
</id>
<version name="version" type="long" unsaved-value="null"/>
<component name="addressComponent">
<property name="street1" type="string" not-null="true"/>
<property name="street2" type="string"/>
<property name="city" type="string" not-null="true"/>
<property name="state" type="string" not-null="true"/>
<property name="zip" type="string" not-null="true"/>
</component>
<property name="cardType" type="string" not-null="true"/>
<property name="cardNumber" type="string" not-null="true" unique="true"/>
<property name="expiry" type="calendar" not-null="true"/>
<property name="securityCode" type="string"/>
<property name="nameOnCard" type="string" not-null="true"/>
<many-to-one name="customer" column="customerId" lazy="true" class="Customer"/>
</class>
Full stack trace of any exception that occurs:Code:
DEBUG - could not delete: [com.allegrocentral.tandoori.beans.CreditCard#1] [delete from creditcard where id=? and version=?]
java.sql.SQLException: Cannot delete or update a parent row: a foreign key constraint fails
at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:2847)
at com.mysql.jdbc.MysqlIO.sendCommand(MysqlIO.java:1531)
at com.mysql.jdbc.ServerPreparedStatement.serverExecute(ServerPreparedStatement.java:1347)
at com.mysql.jdbc.ServerPreparedStatement.executeInternal(ServerPreparedStatement.java:958)
at com.mysql.jdbc.PreparedStatement.executeUpdate(PreparedStatement.java:1957)
at com.mysql.jdbc.PreparedStatement.executeUpdate(PreparedStatement.java:1880)
at com.mysql.jdbc.PreparedStatement.executeUpdate(PreparedStatement.java:1741)
at com.mchange.v2.sql.filter.FilterPreparedStatement.executeUpdate(FilterPreparedStatement.java:71)
at org.hibernate.persister.entity.BasicEntityPersister.delete(BasicEntityPersister.java:2085)
at org.hibernate.persister.entity.BasicEntityPersister.delete(BasicEntityPersister.java:2227)
at org.hibernate.action.EntityDeleteAction.execute(EntityDeleteAction.java:59)
at org.hibernate.engine.ActionQueue.execute(ActionQueue.java:239)
at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:223)
at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:141)
at org.hibernate.event.def.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:274)
at org.hibernate.event.def.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:27)
at org.hibernate.impl.SessionImpl.flush(SessionImpl.java:675)
at com.allegrocentral.tandoori.persistence.utils.DBManager.commitTransaction(DBManager.java:55)
at com.allegrocentral.tandoori.persistence.daos.TestDestination.testInsertDeleteDestination(TestDestination.java:127)
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 org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:421)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:305)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:186)
Name and version of the database you are using: MySQL 4.1.10-nt