Quote:
What are the best practices for this situation ? IMHO, I cannot leave my session open, since, this could take to long before it is closed again.
then again, if I need some data out of this (lazy loaded) collection, how can I retrieve it , when my Session is already closed ?
I came to a solution -i still don't know wether it's good or not- for this problem which does not relies on using NHibernate inside the entity.
The idea is the following:
In the entity, I hold a delegate which will be invoked if the lazy collection is not loaded. This delegated has to be set by the Data Access Layer when loading the entity. The method that is pointed by the delegate (which lives in the Data Access Layer) knows how to load the collection from the database and put it in the entity.
It will be easer to understand if you see the code. Supose you have a Customer entity which holds an Accounts collection.
In the entity:
Code:
// Loaded flag
private bool _areAccountsLoaded;
private IList _accounts;
private AccountsLoaderCallBack _loader;
public delegate void AccountsLoaderCallBack(Customer obj);
public IList Accounts
{
get
{
// Manual lazy loading
if (!_areAccountsLoaded)
{
_loader(this);
_areAccountsLoaded = true;
}
return _accounts;
}
set
{
_accounts = value;
}
public AccountsLoaderCallBack AccountsLoader
{
set
{
_loader = value;
}
}
In the Customer Data Access Layer:
Code:
public static Customer GetById(int id)
{
// Open session...
Customer obj = (Customer)session.Load(typeof(Entities.Customer),id);
// Add the reference to the method that knows how to load the lazy collection manually
obj.AccountsLoader = new Entities.Customer.AccountsLoaderCallBack(PopulateAccounts);
// Close session...
return obj;
}
public static void PopulateAccounts(Customer obj)
{
// Open session again...
// Load accounts. I'm not attaching the object to the session because that would load all the linked data of the entity. I just need the accounts.
obj.Accounts = session.CreateQuery("from Account a where a.CustomerId = :parent")
.SetInt32("parent", obj.Id).List();
// Close session...
}
Also in you customer.hbm.xml you have to use access="field" for the accounts property, because if not, NHibernate will execute the code on initialization.
What do you think about this solution?
Mariano Szklanny
Buenos Aires, Argentina.