Coding and Dismantling Stuff

Don't thank me, it's what I do.

About the author

Russell is a .Net developer based in Lancashire in the UK.  His day job is as a C# developer for the UK's largest online white-goods retailer, DRL Limited.

His weekend job entails alternately demolishing and constructing various bits of his home, much to the distress of his fiance Kelly, 3-year-old daughter Amelie, and menagerie of pets.

TextBox

  1. Fix dodgy keywords Google is scraping from my blog
  2. Complete migration of NHaml from Google Code to GitHub
  3. ReTelnet Mock Telnet Server à la Jetty
  4. Learn to use Git
  5. Complete beta release FHEMDotNet
  6. Publish FHEMDotNet on Google Code
  7. Learn NancyFX library
  8. Pull RussPAll/NHaml into NHaml/NHaml
  9. Open Source Blackberry Twitter app
  10. Other stuff

NHibernate Error "Object references an unsaved transient instance" - Fixed!

Hi all,

Just a quick post to share some learnings I've had around a good ol' NHibernate "Object references an unsaved transient instance" error message. In essence, this message is telling you that you're trying to save an object which has a reference to another unsaved object, and NHibernate for one reason or another is unable to work out which object to save first so that it can work out the ID to apply to the other end of the reference. What went wrong and how did I fix it?

First off, thanks to the author of http://cagataycivici.wordpress.com/2005/11/15/p_i_ve_faced_with/ for giving me my initial steer with this. Now on to my specific example.

Some Background - What Got Me Into This Mess

When we use NHibernate here we've got a single object graph that we pass around and manipulate parts of.  This object graph is a collection of mappings that have references between one-another, to represent the foriegn key relationships in your database. For simplicity sake, let's say our object looks something like the following:

Order - Order
Order.Items - IList<Item>
Order.Items.DeliveryStatusAudit - IList<DeliveryStatusAudit>

This is a collection of three objects (Order, Item and DeliveryStatusAudit) with three corresponding mappings to three corresponding database tables. When we work with our Order we let NHibernate manage the loading and saving of the properties, sub-objects, sub-properties, etc. But that there DeliveryStatusAudit property hanging off of the Item is something different. Because this is an audit list, we don't want to load this data most of the time. So our mapping files look like the following:

<class name="Order" table="tbl_Order">
    <id name="Id" column="orderId" />
    <bag name="Items">
        <key column="itemId" />
        <one-to-many class="Item" />
    </bag>
</class>

<class name="Item" table="tbl_Item">
    <id name="Id" column="itemId" />
    <many-to-one name="SalesOrder" class="Order" cascade="save-update" column="orderId" />
<class>

<class name="DeliveryStatusAudit" table="tbl_DeliveryStatusAudit">
    <id name="Id" column="itemId" />
    <many-to-one name="Item" class="Item" column="itemId" />
<class>

There are two important points to note here:

  1. Our Order has a "bag" of Items, but our Item mapping does not have a bag of DeliveryStatusAudit classes. This is not the cause of our problem, but hints that there's something different about the relationship with the DeliveryStatusAudit class.
  2. The many-to-one relationship "Item -> Order" states a "cascade" property, while with our "DeliveryStatusAudit -> Item" relationship does not. This is the root cause of the problem, which we either work around or we add this property.

The Two Possible Fixes 

Options 1 - Add a "cascade" property to your relationship. If you have a many-to-one relationship between two classes, if you have a cascade on that relationship, an attempt to save an object on the "many" side will automatically save the "one" and any associated classes by spidering through the graph.  This may not be good news if you have a small object referencing a much bigger graph, as in our case!

Option 2 - Save Things in the Right Order. If you do not have a cascade on this relationship, and you try and save a Many before you've saved the One (a DeliveryStatusAudit record before you've saved the Item), NHibernate will not do anything clever for you, you'll get a lovely "Object references an unsaved transient instance" error. I'm guessing that your DeliveryStatusAudit record will have a null ItemId property, which your database will of course expect to be a FK referring to a valid existing Item.


Categories: Sneaky Bug Fixes
Permalink | Comments (0)

Add comment

  Country flag

biuquote
  • Comment
  • Preview
Loading