Minimal and correct way to map one-to-many with NHibernate

Just few hints, summarizing the most suitable standards I found out when working with NHibernate.

1) If there is a bi-directional reference in persitence (DB column), express it in C# code bi-directional as well.

Other words, if a child has reference to parent, parent should have reference to child.

public class Employee
{
    ...
    public virtual IList<Address> { get; set; }
}
public class Address
{
    ...
    public virtual Employee Employee { get; set; }
}

This represents Business Domain as is. Address belongs to Employee and Employee belongs to Address.

If we for some reasons really want to restrict that, we should rather protected modifier, but still keep the reference in C#

2) Use inverse="true". This could be used only if we mapped both sides (as above), and will lead to more “expected and optimized” INSERT and UPDATE scritps

Read more here:

inverse = “true” example and explanation by mkyong

3) Use batch fetching mapping almost everwhere. That will avoid 1 + N issues during querying. Read more:

few details about batch fetching

4) In case, that one object (in our case Employee) is root (the other does not make so much sense without it) – use cascading. Read more:

nhibernate – Create child by updating parent, or create explicitly?

Rules 2,3,4 in a mapping snippets:

<class name="Employee" ... batch-size="25">
  ...
  <bag name="Addresses"
       lazy="true" 
       inverse="true" 
       batch-size="25" 
       cascade="all-delete-orphan" >
    // wrong! This columns is the same as for many-to-one
    //<key column="AddressId" />
    // it is the one column expressing the relation
    <key column="EmployeeId" />
    <one-to-many class="Address" />
  </bag>

<class name="Address" ... batch-size="25">
  ...
  <many-to-one not-null="true" name="Employee" column="EmployeeID" />

3) if we use inverse="true do not forget to assign both sides of relation (mostly critical during creation)

The reason is:

we instruct NHibernate – the other side (Address) is responsible for persisting relation. But to do that properly, that Address needs to have reference to Employee – to be able to persist its ID into its column in Address table.

So this should be the standard code to create new Address

Employee employee = ... // load or create new
Address address = new Address 
{
    ...
    Employee = employee, // this is important
};
Employee.Addresses.Add(address);
session.SaveOrUpdate(employee);  // cascade will trigger the rest

We can also introduce some method like AddAddress() which will hide this complexity, but setting both sides is a good prectice.

Leave a Comment