<< back to blog

NHibernate: Calling Update Unnecessarily

Jun 11, 2009, nhibernate ~ .net

I often see code that looks a bit like this:

public ActionResult UpdatePost(int id, FormCollection form)
{   
    // we won't worry about where _nhibernateSession 
    // comes from for this example.

    var post = _nhibernateSession.Load<Post>(id);
    post.Title = form["PostTitle"];
    post.Body = form["PostBody"];
    _nhibernateSession.Update(post); 
    _nhibernateSession.Transaction.Commit();
}

Can you see what's wrong here? The call to _nhibernateSession.Update(post) is useless.

Why? Because the NHibernate session already knows that the object is being changed. NHibernate tracks objects so it can know if any changes need writing to the database.

A call to Update is used to tell NHibernate to start tracking an object that it is not being tracked already (aka detached object). In the example above, the Post is loaded from the NHibernate session, and is already being tracked. Calling Update on an object that is already being tracked is silly.

It's easy to think that Update signals NHibernate to save changes to the database - to instantly flush them. This is not the case. Update simply indicates an object has changes to be saved, not when they are saved. Don't use Update in an attempt to trigger an instant flush, that's what Flush and Commit are for.

Your code will look cleaner without Updates all over the place. Consider this: our latest NHibernate driven MVC app makes zero calls to Update. We don't need Update because we don't have a scenario where we detach and attach objects to the NH session. All functionality can be achieved though Save, Commit and Rollback.

The previous example should really just exclude the redundant Update as follows:

public ActionResult UpdatePost(int id, FormCollection form)
{   
    var post = _nhibernateSession.Load<Post>(id);
    post.Title = form["PostTitle"];
    post.Body = form["PostBody"];   
    _nhibernateSession.Transaction.Commit();
} 

When Update Is Required

So when is an Update required? Here's a valid use of Update:

public ActionResult UpdatePost(int id, FormCollection form)
{   
    var post = HttpContext.Session[id] as Post;
    post.Title = form["PostTitle"];
    post.Body = form["PostBody"];
    _nhibernateSession.Update(post);    
    _nhibernateSession.Transaction.Commit();    
}

Here, the Post is pulled out of the Http session -- it is not being tracked yet. Then, it's properties are changed, and Update is called. The object is re-associated with the session, and NHibernate will assume that it needs saving even though it observed no changes after re-association. In other words, Update implies a save is required (Lock can be used to associate an object with the session without making NHibernate assume a save is required).

The call to Update is valid when a detached object is being re-associated with a session, and you want the session to assume the object has changed.

This variation will also work:

public ActionResult UpdatePost(int id, FormCollection form)
{   
    var post = HttpContext.Session[id] as Post;
    _nhibernateSession.Update(post); // <-- 
    post.Title = form["PostTitle"];
    post.Body = form["PostBody"];   
    _nhibernateSession.Transaction.Commit();    
}

The end result is the same, but because Update is called before the changes are applied to the object, NHibernate will waste CPU cycles tracking the changes made after the call to Update before finally flushing them to the database. It's not bad, just a tad wasteful.

You may also like...

blog comments powered by Disqus