NHibernate and default constructors

One of the first things you learn about NHibernate is that in order for it to be able to construct your instances and take advantage of lazy loading every persistent class must have the default, parameterless constructor. This leads to having entities looking like this (standard blog with posts and comments example).

 public class Post { private readonly IList<comment> comments = new List<comment>();
    private Blog blog;

    [Obsolete("For NHibernate")]
    protected Post()
    {
       
    }

    public Post(string title, string body, Blog blog)
    {
        Blog = blog;
        Title = title;
        Body = body;
        Published = DateTimeOffset.Now;
    }

    public virtual int Id { get; private set; }
    public virtual DateTimeOffset Published { get; private set; }

    public virtual string Title { get; set; }
    public virtual string Body { get; set; }


    public virtual IEnumerable<comment> Comments
    {
        get { return comments; }
    }

    public virtual Blog Blog
    {
        get { return blog; }
        set
        {
            if (blog != null)
            {
                throw new InvalidOperationException("already set");
            }
            blog = value;
            if (blog != null)
            {
                blog.AddPost(this);
            }
        }
    }

    [EditorBrowsable(EditorBrowsableState.Never)]
    protected internal virtual void AddComment(Comment comment)
    {
        comments.Add(comment);
    }
}

Notice the first constructor. It doesn’t do anything. As the obsolete message (which is out there to get compilation warning in case some developer accidently calls this constructor in their code) points out – this constructor is there only so that NHibernate can do its magic. Some people do put there initialization logic for collections, (especially when you use automatic properties) but I use fields and initialize them inline. In that case the constructor is pretty much useless. I started thinking why is it even there and that perhaps it doesn’t really belong to the class. But let’s start at the beginning.

What is a constructor

As basic as the question may seem, it is useful to remind ourselves why we need constructors at all. The best book about C# and .NET defines them as follows:

Constructors are special methods that allow an instance of a type to be initialized to a good state.

Notice two important things about this definition. First, it doesn’t say that constructor creates the instance or that constructors are the only way to create the instance. Second, constructors initialize newly created object to their initial state so that anything that uses the object afterwards deals with fully constructed, valid object.

Constructors and persistence

The above definition very well applies to the other constructor we have on the Post class. That constructor initializes the Post to a valid state. In this case valid means the following.

  • Post is part of a blog – we can’t have a post that lives on its own. Our posts need to be part of a blog and we make this requirement explicit by requiring a Blog instance to be provided when constructing Post.
  • Post requires a title and a body and that’s why we also require those two properties to be provided when constructing a post.
  • Posts are usually displayed in a inverse chronological order hence we set the Published timestamp.

We do none of the above in the other, “nhibernate” constructor. That means that according to the definition of a constructor it is not really doing what a constructor is supposed to be doing. It is never used to construct an object.

Hydration

Let’s take a step back now. What NHibernate is doing with objects in nutshell is serialization. You create an object in your code and initialize it using constructor, do some stuff with it and then you save the object away, so that it can be retrieved later, after your app has been closed, or perhaps on another server instance. You save away the state of the object so that the state representation of the object can live longer than volatile, in-memory representation of the object. If you follow this path of though the next obvious conclusion is that if you have a load-balanced system and two server instances work with Post#123 they both are dealing with the same object, even though they are two separate machines.

The conclusion of that is that when NHibernate is retrieving an object from the persistent store it is not constructing it. It is recreating an in-memory representation of an object that had been created and persisted previously. Hence we are merely recreating object that already has a well known state and had been initialized and just providing different representation for it. This process is called hydration.

Persistent and Volatile state

The full picture is a bit more complicated than what I painted so far. The database and in-memory object are two representation of the same entity but they don’t have to be fully one to one. Specifically it is possible for the in-memory representation to have state beyond the persistent state. In other words the in-memory object may have some properties that are specific to it, and not relevant to the in-database representation. A convenient example that most people will be able to relate to would be a logger. Please don’t quote me as advocating using logging in your entities but logger is one of the things you may want to have on your in-memory object and use it while executing code in your application but then let them go once you no longer need the object and not persist them. If we had one in the Post class the empty constructor would change to the following:

[Obsolete("For NHibernate")]
protected Post()
{
    logger = LoggerProvider.LoggerFor(typeof(Post));
}

If we don’t use constructor for recreation of the object, how can we get the logger in? How do we make NHibernate hold the contructor semantics and give us fully initialized object? Remember I said one way of looking at NHibernate from the object’s perspective is that’s just a fancy serializer/deserializer. Turns out serialization mechanism in .NET offers us four(that I know of, possibly more) ways of tacking this issue

  • you can use serialization surrogate that knows how to recreate the full state of the object
  • you can use deserialization callback interface to be notified when the object has been fully deserialized and then initialize the volatile state.
  • you can use serialization callback attributes to be notified when various steps in the serialization/deserialization process happen and initialize the volatile state.
  • you can use ISerializable interface and implement serialization constructor which is used to deserialize the object.

Notice that only one of those approaches uses special constructor. Since as we discussed NHibernate doesn’t really need the default constructor (in theory that is), can we really get rid of it? Turns one we can (in most cases), and we’ll look at how to do it in the next post.

Comments

Scooletz says:

I’m really interested in your future post about this case! I’ve written a series of posts about IInterceptor, with the final located here: http://blog.scooletz.com/2011/02/24/nhibernate-interceptor-magic-tricks-the-example/ This may cover a part of topic you will discuss.

[…] Proxy Tutorial « NHibernate and default constructors […]

[…] the previous post we established that the usage of default constructor required by NHibernate is theoretically not […]