A few tips summarizing the most appropriate standards that I found out when working with NHibernate.
1) If there is a bidirectional link in persitence (DB column), express it in C# code bidirectional .
Other words, if the child has a link to the parent, the parent must have a link to the child.
public class Employee { ... public virtual IList<Address> { get; set; } } public class Address { ... public virtual Employee Employee { get; set; } }
This is the business domain as it is. Address belongs to Employee and Employee belongs to address.
If for some reason we really want to limit this, we should probably use the protected modifier, but save the link in C#
2) Use inverse="true" . This can only be used if we have matched both sides (as indicated above) and lead to more “expected and optimized” INSERT and UPDATE sweeps
More details here:
inverse = "true" example and explanation from mkyong
3) Use batch sampling mapping almost always. This will avoid problems with 1 + N during queries. More details:
some details about batch sampling
4) In case one object (in our case Employee) is equal to root (the other without much sense without it) - use cascading. More details:
nhibernate - create a child by updating the parent or create explicitly?
Rules 2,3,4 in display fragments:
<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 , remember to assign both sides of the relationship (mostly critical when creating)
The reason is this:
we instruct NHibernate - the other side ( Address ) is responsible for the continuing relationship. But for this, it is enough that Address needs a link to Employee - to save its identifier in its column in the address table.
So this should be the standard code to create a 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() that will hide this complexity, but setting both sides is a good prefix.