Hibernate - clearing a collection with all-delete-orphan and then adding to it causes ConstraintViolationException
hibernate, unique-constraint
Solution
I guess there is no alternative to flushing
From here:
Hibernate is violating a unique constraint!
Hibernate isn't quite as clever with unique constraints as it is with foreign keys. Sometimes you might need to give a little hint.
A unique constraint violation could occur if two objects are both being updated, one is "releasing" a value and the other is "obtaining" the same value. A workaround is to flush() the session manually after updating the first object and before updating the second.
(This kind of problem occurs rarely in practice.)
Problem
I have these entities ``` class Foo{ Set<Bar> bars; } class Bar{ Foo parent; String localIdentifier; } ``` With this mapping (sorry, no annotations, I'm old fashioned): ``` <class name="Foo"> ... <set name="bars" cascade="all-delete-orphan" lazy="false" inverse="true"> <key>...</key> <one-to-many class="Bar"/> </set> </class> <class name="Bar"> ... <property name="localIdentifier" column="local_identifier"/> <many-to-one name="parent" column="parent_id" /> </class> ``` I also have a unique constraint on 2 columns: `local_identifier` and `parent_id` (not a unique constrain on each, but a single unique constrain containing both, e.g. no 2 rows with the same parent and same localIdentifier are allowed) ``` alter table bar add constraint unique_bar unique (parent_id, local_identifier) ``` And this code that uses them: ``` //foo is persistent, foo id = 1 Bars bars = foo.getBars(); bars.clear(); // bars contained 1 item [parent_id = 1, local_identifier = "a"] Bar newBar = new Bar(); newBar.setParent(foo); newBar.setLocalIdentifier("a"); bars.add(newBar); ``` Now, for some reason, Hibernate doesn't execute things in the order they were called. It doesn't execute the `clear()` (delete) before the `add()` (insert) but vice versa, it first tries to insert, getting a `ConstraintViolationException` I know adding a little `session.flush()` after `bars.clear();` , could fix this, but in this case, I have no access to the session in a non ugly way. So is flush is the only solution? or is there a Hibernate version that respects the order of actions? Update: By the way, dereferencing the collection will result in a HibernateException from https://www.hibernate.org/117.html#A3: I get HibernateException: Don't dereference a collection with cascade="all-delete-orphan" This will happen if you load an object with a cascade="all-delete-orphan" collection and then remove the reference to the collection. Don't replace this collection, use clear() so the orphan-deletion algorithm can detect your change.