Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

When to use inverse=false on NHibernate / Hibernate OneToMany relationships?

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?

like image 826
James Allen Avatar asked Jun 30 '09 00:06

James Allen


3 Answers

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.

like image 130
Nigel Avatar answered Oct 16 '22 01:10

Nigel


Despite of the high-voted accepted answer, I have another answer to that.

Consider a class diagram with these relations:

Parent => list of Items
Item => Parent

Nobody ever said, that the Item => Parent relation is redundant to the Parent => Items relation. An Item could reference any Parent.

But in your application, you know that the relations are redundant. You know that the relations don't need to be stored separately in the database. So you decide to store it in a single foreign key, pointing from the Item to the Parent. This minimal information is enough to build up the list and the reference back.

All you need to do to map this with NH is:

  • use the same foreign key for both relations
  • tell NH that one (the list) is redundant to the other and could be ignored when storing the object. (That is what NH actually does with inverse="true")

These are the thoughts which are relevant for inverse. Nothing else. It is not a choice, there is only one way of correct mapping.


The Spy Problem: It is a completely different discussion if you want to support a reference from the Item to the Parent. This is up to your business model, NH doesn't take any decisions in this. If one of the relations is missing, there is of course no redundancy and no use of inverse.

Misuse: If you use inverse="true" on a list which doesn't have any redundancy in memory, it just doesn't get stored. If you don't specify the inverse="true" if it should be there, NH may store the redundant information twice.

like image 23
Stefan Steinegger Avatar answered Oct 15 '22 23:10

Stefan Steinegger


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.

like image 32
MatthieuGD Avatar answered Oct 16 '22 00:10

MatthieuGD