Detached objects in nHibernate and Lazy loading

Hopefully we all know what the definition of persistent and transient objects are when speaking of Object/Relational Mapping, if not here is a quick description: A Transient object is an instance either fetched from the database and then deleted at a later point or an object not fetched using the O/R mapper. For instance if you create an instance of a class using its defualt empty constructor this will be a transient object. A Persistent object is an instance fetched from the O/R mapper which contains data from the database, the O/R mapper tracks changes to this instance so it can be syncronized with the underlying datastore later.

However a third "type" of objects exist when working with for instance nHibernate, a detached object. A Detached object is a persistent instance that has lost its association with the O/R mapper(The O/R mapper no longer knows the object is probably a better way to say it as the object knows nothing about the O/R mapper), in the case of nHibernate this would be that the ISession that you used to fetch the object is no longer available/open. This has some consequences:

  1. The object can not be saved to the database like you normally do
  2. If the object has properties that needs to be initialized from the database using lazy-loading this will fail

When we use nHibernate in a web context, that is for developing a website, the most common thing is to use a ISession pr request, but what if we want a persistent object to live across request? That could be in a either Application, Session or Viewstate. First of all we have to think if that's  really what we want, in most cases it doesn't make much sense, but in some cases its just what you want to do! Fortunately nHibernate provides features to reattach a detached instance to a new ISession, it as simple as:

ISession.Lock(myDetachedInstance, NHibernate.LockMode.None); 

Of course this is only sound to do if you are sure the object has not updated between requests, if there is a chance it has changed you can use the Update method instead:

ISession.Update(myDetachedInstance); 

After reattaching an instance, properties that are lazy initialized can be accessed normally and the data is loaded lazy using the new ISession.

But be aware that Session is no place for caching general data as it is pr-user, but instead you can use a second-level cache. This is supported in nHibernate using the different cache providers found in the NHibernate.Caches project, in web context this is extremly helpful because the second-level cache caches data across multiple requests and multiple ISession's, so "frequently-used rarely-changed data" can be retrieved from memory instead of hitting the database.


Comments

September 21. 2007 10:20 AM

Simon Clemen Pedersen

Nice post mate. However I would generally (in a OO-context) define a transient object as an object which ceases to exist when the process that created it ceases to exist. In a DB context the detached behaviour is of course also important.

Is there a simple way to compare a detached object with the data in the database - to view the diff?

Simon Clemen Pedersen

September 21. 2007 07:52 PM

Jakob Andersen

Of course in OO context and database context transient and persistent have different meanings. But in the context of OR-mapping i think the definitions above is pretty sound.

All information about the objects previous state is no longer existing when its "mother"-session is gone. So associating the object with the session again just performs a version check

Jakob Andersen

Comments are closed