Foreign Key is always 0 (zero) when inserting Parent Child using NHibernate

This one was a toughy. I searched for some time looking for examples about HOW TO: INSERT PARENT / CHILD RELATIONSHIPS using NHIBERNATE. What I found were these really cool looking object oriented AddChild methods, many-to-one and one-to-many mapping relationships. The thing about those examples is that they do not take into account legacy database structures. Most of the articles I found were really a regurgitation of the original Hibernate documentation.

My opinion is that most examples using what I mentioned above come from a DDD approach (Domain Driven Design), when the mappings and classes are created before the database. However, historically, most programs are designed from a database point of view first. This is a significant change in approach.

Anyway, after much trial and error using inverse=”true”, cascade=”all” and all the other tips I finally got the insert to work for both the Parent and the Child using some relatively good code.

Parent theParent = new Parent { Name = "Ben Perkins" };
theParent.theChildren.Add(new Child { Name = "Lea Perkins" });
session.Save(theParent);

Without inverse=”true” the child was not being inserted.

Without inverse=”true” but with cascade=”all” everything seemed to work out (WIHTOUT A FOREIGN KEY REQUIREMENT) however it resulted in an INSERT of the CHILD with an ID = 0 and then an UPDATE to set the actual FOREIGN KEY value. The INSERT failed once the FOREIGN KEY was applied.

When I used neither inverse=”true” nor cascade=”all” I received this error: object references an unsaved transient instance – save the transient instance before flushing. Type: Namespace.Class, Entity: Namespace.Class

Using both inverse=”true” and cascade=”all” resulted in 2 INSERTS but the FOREIGN KEY ID was 0, again no go when FOREIGN KEY constraint is applied.

So many different error messages, so many possible options. My initial option was to save the PARENT, then explicitly access the PARENT.ID variable and use it to as the FOREIGN KEY when I again explicitly saved the CHILD. It worked and it worked with only 2 INSERT statements. However, it just didn’t seem right.

Simply, my approach was wrong because I tried implementing a DDD onto a legacy database. When approaches are incorrect from the beginning, and we have deadlines, incorrect decisions are made, just because they work (I.e. explicitly using the PARENT.ID and calling save twice)

To see how I ultimately did it using a composite-element, check out my other blog here.

A detailed description of how I implemented this can be found in my book.