Its one of those things – you have the same problem every now and then, but not often enough to remember what the solution was.
I was implementing some hibernate code, but the tests for it failed due to primary key constraint exception (basically hibernate was trying to save already save object using same primary key). I can clearly remember that i have seen this exception before, but the cause and solution were lost somewhere between all those NonUniqueObjectExceptions and jsp exceptions that i had problems with few weeks ago
.
So i had to dig into in once more, and promise to myself that i will blog it after i diagnose the problem, so i don’t forget about it ever again (and save someone else the trouble as well). So here it is:
The domain model and hibernate mapping were really basic – Descriptor object has reference to List of Note objects:
public class Descriptor{
private Long id;
private List<Note> notes = new ArrayList<Note>;
public void addNote(Note note){
note.setDescriptor(note);
this.notes.add(note);
}
//getters and setters omitted for clarity
}
public class Note{
private Long id;
private String text;
private Descriptor descriptor;
//getters and setters omitted for clarity
}
<class name="Descriptor" table="t_descriptor">
<id name="id" type="long" unsaved-value="null">
<generator class="sequence">
<param name="sequence">s_descriptor_id</param>
</generator>
</id>
<list name="notes" cascade="all"
<key column="descriptor"/>
<index column="id"/>
<one-to-many class="Note"/>
</list>
</class>
<class name="Note" table="t_note">
<id name="id" type="long" unsaved-value="null">
<generator class="sequence">
<param name="sequence">s_note</param>
</generator>
</id>
<property name="text" column="text" not-null="true"/>
<many-to-one name="descriptor" column="descriptor" not-null="true"
class="Descriptor"/>
</class>
Looks simple, but when i run the test for the code above, i got dreaded primary key unique constraint exception.
After a bit of though, i was able to kick myself for not noticing the problem:
The notes property of Descriptor class is mapped with cascade=”all” meaning all save, updates, deletes with apply for the child objects as well. However, the inverse is set to false (inverse property is missing, defaults to inverse=”false”) – making both sides of the bi-directional relationship responsible of taking care of the relationship. SO Hibernate generates two insert statements, one because of cascade=”all”, and one as part of inverse=”false” rule.
The solutions is to set inverse=”true” on notes property mapping – this will make just one side of bi-directional relationship responsible for relationship, and the Hibernate will issue just one insert statement for the Note object.
Here is the correct piece of mapping:
<list name="notes" cascade="all" inverse="true">
<key column="descriptor"/>
<index column="id"/>
<one-to-many class="Note"/>
</list>
Huh! Cascade and inverse properties when mapping collections in hibernate simplify the development, and improve performance if used correctly, but beware of the pitfalls of unsuspected exception.
To read more go to the Hibernate website or read this blog: http://www.codeweblog.com/hibernate-in-the-inverse-and-cascade/

Pingback: Dcs Replacement Parts
Hi, thanks and guest blogs are welcome, we are putting more time into our blogs in the coming weeks so please stay tuned!