4

My Db is throwing a Constraing violation (FK) because Hibernate performs a cascade delete in the wrong order.

Details: I delete a Member, that has a Wallet with Wallet transactions (value-type), and the wallet transaction has an association to a product just like the Member contains collection of products (see the Hibernate mapping below).

I delete a Member instance, and want Hibernate to remove both the products and Wallet transactions. It seems that it first removes the product instances (through cascading), such that a FK violation is thrown by the DB, as it's still referenced by a Wallet transaction, that wasn't removed yet (through cascade)

I played around with the cascade setting, like all-delete-orphan (on the products), etc..., but no luck I also emptied the wallet transactions and flushed the hibernate session in the same removal transaction, but also the same error.

Please some understanding and help to get the order of cascade deletion correct?

The hibernate mapping (I left out the none-important parts like PK and properties):

<class name="Member" table="mem" >
 <component name="wallet" class="Wallet">
  <set name="transactions" table="wallet_tx" cascade="all">
   <cache usage="read-write" />
   <key column="idTaxer" not-null="true" />
   <composite-element class="WalletTransaction">
    <property name="amount" type="big_decimal" column="amount" />
    <many-to-one name="product" column="idPrdInst" class="Product" cascade="none" />
   </composite-element>
  </set>
 </component>

 <set name="products"  cascade="delete" inverse="true">
  <key column="idTaxer" not-null="true" />
  <one-to-many class="Product" />
 </set>
</class>

<class name="Product" table="prd" >
 ...
 <many-to-one name="member" column="idMember" class="Member" cascade="none" />
</class>

The DB error:

ERROR:  update or delete on table "prd" violates foreign key constraint "fk_1umej7" on table "wallet_tx"
DETAIL:  Key (id)=(75bef42fc4544) is still referenced from table "wallet_tx".
Vlad Mihalcea
  • 142,745
  • 71
  • 566
  • 911
edbras
  • 4,145
  • 9
  • 41
  • 78

2 Answers2

1

If you empty the wallet transaction and expect it to be deleted you must set delete-orphan on the transactions relationship.

If product is still deleted 1st, you can flush after removing the wallet tx from the transaction set, it will work but it's surely not the state-of-art way.

Otherwise you could try to map the product - transaction oneToMany relationship and set a delete cascade on it (with inverse), the product deletion will so first trigger the transaction deletion.

Gab
  • 7,869
  • 4
  • 37
  • 68
  • how would the "product - transaction oneToMany" mapping look in xml mapping? The other options I tried already and don't work (orphan deletion on the transation won't change the first-deletion of the products). Thanks. – edbras Jun 06 '14 at 22:26
1

Instead of:

<set name="transactions" table="wallet_tx" cascade="all">

you should have:

<set name="transactions" table="wallet_tx" cascade="all-delete-orphan">

And simply clear the transactions Set prior to deleting the Member parent entity.

Vlad Mihalcea
  • 142,745
  • 71
  • 566
  • 911
  • Sorry for the late answer. I was busy solving many other bugs. Currently I can't seem to reproduce the problem, a bit frustrating :( I extended the unit test to represent well the described problem, but no luck. If it will appear, I will come back on this issue of course. Currently it's working with the mapping above, without emptying the transaction collection first. In the log I noticed it's generating the sql queries in the correct order. BTW: your proposal I tried before, but back then didn't solve the problem. Sorry.. – edbras Jun 10 '14 at 13:31
  • The problem appears again, I am trying to solve it, but no luck. Your solution doesn't work, no idea why, maybe because of the extra link back from product to member, strange... Any idea? – edbras Jul 08 '14 at 09:59
  • But it's an embeddable, you don't have a bidirectional association. – Vlad Mihalcea Jul 08 '14 at 10:19
  • 1
    I solved it: I was making the contained set null instead of empty such that Hibernate couldn't track it anymore. Similar to this issue: http://stackoverflow.com/questions/5587482/hibernate-a-collection-with-cascade-all-delete-orphan-was-no-longer-referenc – edbras Jul 09 '14 at 09:46
  • @edbras You should put this comment as an answer and accept it – Gab Oct 02 '14 at 22:06