There isn't much in the way of a definitive solution or best practice for lazy loading in a tiered app that I have been able to find. After a few months of playing, this is how I solved the problem.
I have a base DAO object which I use to wrap NHibernate sessions, session factory, etc. In this object I have a static method for initializing a lazy collection:
public static IList reconnectSession(object obj, IList aCollection)
{
bool loaded = false;
ISession sess = null;
try
{
PersistentCollection tCollection = aCollection as PersistentCollection;
if (tCollection != null && !NHibernateUtil.IsInitialized(tCollection))
{
sess = DataAccessManager.Instance().Session;
sess.Lock(obj,LockMode.None);
NHibernateUtil.Initialize(tCollection);
loaded = true;
}
}
catch (Exception e)
{
m_Logger.Error("Error lazy loading collection for obj " + obj.GetType(),e);
}
finally
{
if (loaded)
sess.Disconnect();
}
return aCollection;
}
In my DTO's, in the getter for each lazily loaded collection, I have code similar to the following:
public IList Addresses
{
get {
return BaseDAO.reconnectSession(this,m_Addresses);
}
set {m_Addresses = value;}
}
Now, when your UI layer accesses the collection (binding to a datagrid or list, etc), the getter is called, the collection is initialized and a hydrated colection is returned. Your UI knoes nothing of the NHibernate layer.
A couple of notes about this code, In the ReconnectSession method, DataAccessManager is simply a class that maintains a static SessionFactory for me to pull sessions from.
Also, and most important, the sess.Lock() call will reload all propoerties of the object that you are locking on. So, if your are using property access within your mapping file (default) the getter for your lazy collection will be called again, resulting in anoth call to Lock(), calling the getters, etc creating an infinite loop. You must set the access on the class in your mapping file to something other than property. I am using
default-access="field.pascalcase-m-underscore" in each class declaration that contains lazily loaded collections. This means that if my <property> name in the mapping file is Name, NHibernate will expect a member variable of that property's type in the DTO named m_Name. THe different types of default-access values are listed in the NHibernate docs.
Hope this helps
|