Tigraine

Daniel Hoelbling-Inzko talks about programming

Virtual member call in constructor and NHibernate

Posted by Daniel Hölbling on November 7, 2008

As you may have noticed, I’ve been doing some NHibernate work lately and really had a great time with this absolutely amazing ORM. Especially now that Microsoft abandoned Linq to SQL I really feel good about having made the step towards NHibernate.

Yesterday was one of those tricky days when something breaks and you have no clue why.

I have a table called “Orders” and there are “OrderItems”.

image

By writing the tests upfront, I found out that I’d like to be able to just say Repository.Add(Order) instead of persisting the Order and afterwards looping through the OrderItems and persisting them too.

To achieve this I changed the mapping to something like this:

<set name="OrderItems" cascade="all">
  <key column="OrderId" />
  <one-to-many class="OrderItem"/>
</set>

The cascade=all statement is what I searched for initially. When the order gets persisted, all OrderItems in the collection get persisted too, and everything is well.

But, since my POCO object looks like this:

public class Order
{
    public virtual long Id { get; set; }
    public virtual ISet<OrderItem> OrderItems { get; set; }
}

I got NullReferenceException whenever I tried to access OrderItems on new Order objects. And I thought, hey.. kinda sucks newing up the collection in my business layer, why not init it in it’s constructor:

    public Order()
    {
        OrderItems = new HashedSet<OrderItem>();
    }

So I could just do Order.OrderItems.Add(OrderItem) without having to instantiate a HashedSet anywhere.
I got a bit cautious when Visual Studio underlined OrderItems and made the cryptic announcement: “Virtual member call in constructor”.


Totally unaware of what this means, I just went on and ran my tests.

Imagine my face when almost all my tests failed due to an omnious nHibernateException:

NHibernate.HibernateException: Illegal attempt to associate a collection with two open sessions

I didn’t figure this out until today, but it had to do with the “Virtual member call in constructor” warning. I discovered this post by Brad Abrams that explains the topic.

Looks like if you set the collection in the constructor of the POCO object NHibernate will break with the above Exception.
Solution to avoid this? Init the collection from calling-code instead of within the object.

What would have helped the issue would be to not have concrete POCO objects but rather use interfaces instead of virtual members (Read Fabio Maulo’s post entity-name in action: Entity Abstraction on that topic).

comments powered by Disqus

My Photography business

Projects

dynamic css for .NET

Archives

more