Taming NHibernate Child Collection Persistence
I’ve been using [hacking at] NHibernate as my main ORM choice for just over a year and I’ve been exceptionally happy with the growing number of projects to augment it’s functionality, especially the Fluent NHibernate and LINQ-to-NHibernate contributions. NH isn’t exactly a simple ORM layer and does have some confusing aspects. One of these aspects – at least for me – has been that I’ve seen inconsistent behavior in the persistence of child collection properties. I think I concluded via a series of unit tests this evening for myself how to gain the typical desired outcome and I felt it was something I should share.
Take, for example, the traditional order-to-order-detail relationship. The screenshot below shows a code example of a POCO domain object organization exemplifying this sort of relationship. The Product domain object has been included for the sake of completeness for this discussion.
Following in typical NHibernate/ORM style I’ve created a series of repository interfaces and implementations to provide persistence functionality for these objects; though a discussion of those implementations is somewhat beyond the scope of this article I’m relatively certain that with a bit of ORM and TDD experience the remainder of this text should still make sense. I tend to use base classes when I’m working up my unit tests. The base class below is one that I use in this storefront project example that exposes references to local instances of those repositories. Likewise, it inherits from one of the classes provided via the S#arp architecture, the RepositoryTestsBase class.
Next is an examination of the TDD setup for this domain object hierarchy. Not too complicated an idea, this is the simplest example of a storefront possible. Products are created, then a sample order is created. To the sample order two products, with varying quantities, are added to the order.
The unit tests are also as simple as the setup. Each unit test makes sure each item was saved to the persistence layer, and each bases it’s pass/fail criterion solely on the data loaded via the method in the figure above.
Seems simple enough but when the tests are executed via TestDriven.NET the tests indicate a failure to save the order details simultaneously when the order is persisted.
Now, in the case where you’re like me and you want the children to be saved with the parent, this just won’t do. If you’re of the mindset that each object should be created on it’s own in the persistence layer, this might not be so bad. My point is, the code below should save both of the order detail records withthe order, each time, no matter what.
In this case, my problem was in the way I was mapping the relationship between the Order and OrderDetail classes. I’m using Fluent NHibernate and Auto Mapping, so the changes should be minimal and made within the mapping override for my Order object. The code for my Order mapping override is below.
Once I add in the single line informing the mapping that it should cascade all changes via the Cascade.All() method call, the test passes and the order detail records are created alongside the Order.
If you’re not comfortable with the cascading delete impact this would have the option for cascading only on saves and updates could be a better choice.