views:

3499

answers:

2

I have been trying to get to grips with Hibernate's inverse attribute, and it seems to be just one of those things that is conceptually difficult.

The gist that I get is that when you have a parent entity (e.g. Parent) that has a collection of Child objects using a one-to-many mapping, setting inverse=true on the mapping tells Hibernate that 'the other side (the Child) has responsibility to update itself to maintain the foreign key reference in its table'.

Doing this appears to have 2 benefits when it comes to adding Children to the collection in your code, and then saving the Parent (with cascade-all set): you save an unneccessary hit on the database (because without inverse set, Hibernate thinks it has two places to update the FK relationship), and according to the official docs:

If the column of a association is declared NOT NULL, NHibernate may cause constraint violations when it creates or updates the association. To prevent this problem, you must use a bidirectional association with the many valued end (the set or bag) marked as inverse="true".

This all seems to make sense so far. What I don't get is this: when would you NOT want to use inverse=true on a one-to-many relationship?

+7  A: 

If you want to have an unidirectional association i.e. that the children can't navigate to the Parent. If so, you FK column should be NULLABLE because the children will be saved before the parent.

Matthieu
+17  A: 

As Matthieu says, the only case where you wouldn't want to set inverse = true is where it does not make sense for the child to be responsible for updating itself, such as in the case where the child has no knowledge of its parent.

Lets try a real world, and not at all contrived example:

<class name="SpyMaster" table="SpyMaster" lazy="true">
  <id name="Id">
    <generator class="identity"/>
  </id>
  <property name="Name"/>
  <set name="Spies" table="Spy" cascade="save-update">
<key column="SpyMasterId"/>
<one-to-many class="Spy"/>
  </set>
</class>

<class name="Spy" table="Spy" lazy="true">
  <id name="Id">
    <generator class="identity"/>
  </id>
  <property name="Name"/>
</class>

Spymasters can have spies, but spies never know who their spymaster is, because we have not included the many-to-one relationship in the spy class. Also (conveniently) a spy may turn rogue and so does not need to be associated with a spymaster. We can create entities as follows:

var sm = new SpyMaster
{
    Name = "Head of Operation Treadstone"
};
sm.Spies.Add(new Spy
{
    Name = "Bourne",
    //SpyMaster = sm // Can't do this
});
session.Save(sm);

In such a case you would set the FK column to be nullable because the act of saving sm would insert into the SpyMaster table and the Spy table, and only after that would it then update the Spy table to set the FK. In this case, if we were to set inverse = true, the FK would never get updated.

Nigel
+1 for the novel example, and a comprehensive answer
James Allen