Superfluous update - use inverse='true'

One of the more common mistakes that are made when mapping associations from the database is not setting the proper inverse attribute to let NHibernate know which side of the association is the owner of the association.

This is important because while in the object world, all associations are unidirectional, in the database world, all associations are bidirectional. As a result, NHibernate assumes by default that all associations are unidirectional and require and explicit step (setting inverse='true' on the association to recognize bidirectional associations).

The actual problem is simple, NHibernate issue a superfluous update statement. The NHibernate Profiler is able to detect and warn against such mistake.

Example of the problem:

The following object model shows a very simple bidirectional association. Blog has Posts, Post has Blog.

class diagram

This is mapped to the following table model:

database diagram

Notice that while on the object model this is a bidirectional association and is maintained by two different places, it is maintained on a single place in the database.

This is a very common case, and quite easy it wrong. By default, NHibernate has to assume that it must update the column on both sides, so creating a new post and adding it to the Blog's Posts collection will result in two statements being written to the database:

INSERT INTO Posts(Title,
Text,
PostedAt,
BlogId,
UserId)
VALUES ('vam' /* @p0 */,
'abc' /* @p1 */,
'1/17/2009 5:28:52 PM' /* @p2 */,
1 /* @p3 */,
1 /* @p4 */);

select SCOPE_IDENTITY()


UPDATE Posts
SET BlogId = 1 /* @p0_0 */
WHERE Id = 22 /* @p1_0 */

As you can see, we are actually setting the BlogId to the same value, twice. Once in the insert statement, the second using the update statement.

Now, there is a very easy fix for this issue, all you have to do is to tell NHibernate on the Blog's Posts mapping that this is a collection where the responsibility for actually updating the column value is on the other side. This is also something that I tend to check in code reviews quite often. The fix is literally just specifying inverse='true' on the <one-to-many> collection association.