1
votes

I'm having a few problems with Eager Loading in NHibernate. The first thing I've noticed when starting to maintain this application is they don't seem to eager load anywhere.

My first port of call was Fetch. But this threw an exception saying that it cannot complete that operation when the collection is an IList. Apparently it has to be an ICollection. I can hardly change the domain, just to accommodate Fetch.

Next up, I looked at .Future and .FutureValue. No go there as the provider did not support it.

This left me with NHibernateUtil.Initialize. As a proof of concept, I wrote some code like:

var leppp = _repository.Query<LogbookEntryProcedure>()
    .Where(lep => lep.LogbookEntry.Id == logbookEntryId);

NHibernateUtil.Initialize(leppp.Select(l => l.Complications));
NHibernateUtil.Initialize(leppp.Select(l => l.Magnitude));
NHibernateUtil.Initialize(leppp.Select(l => l.Outcome));
NHibernateUtil.Initialize(leppp.Select(l => l.FollowUps));

var lepp = leppp.Single();    

It did not throw an exception. However, it did not seem to eager load anything. When I looks at Profiler, I could see that round trips were being made to the database for the related objects.

So, how does one do eager loading in NHibernate in these circumstances?

1
"they don't seem to eager load anywhere": yes, that is an usual practice with NHibernate. And even recommended practice by a bunch of people including me. A properly set up NHibernate application does not suffer from N+1 issues with lazy loading. Its code base is lighter, and may even out-perform eager loading on runtime performances. Read more by following those previous links. - Frédéric

1 Answers

2
votes

As stated in my comment, switching to eager loading may not be a good move. Now back to your question topic.

About Fetch: I am not aware of such a limitation. Have you tried with FetchMany instead? May you provide the exact error message? Are you using an old NHibernate version?

Future and FutureValue not supported: hum, which version of NHibernate do you use? It is there: NH-2309, done in NHibernate v3. (Current version is v4.1.1. .Net Framework 4 required, upgrade to v3 instead if your app is not targeting it. Note that the Linq provider is no more an external dependency since v3, it is embedded, just have a using NHibernate.Linq;.)

NHibernateUtil.Initialize: it is not meant to be used on IQueryable. Doing so is just a no-op. Initialize checks if the supplied object is an entity proxy or a collection proxy, and if yes, it initializes it. Otherwise it just does nothing, as this could be a collection or entity which was directly loaded without being proxified first. Queryables are not proxies.
(That re-enforces my belief you should read more on how NHibernate works with lazy-loading, since this utility method is documented for usage with proxies, and proxies are there for lazy-loading. Especially check "Improving Performances - Using batch fetching", which is indeed "batching lazy-loads".)

So, if you really need eager fetching, with Linq, while using an old version of NHibernate (< v3), with your domain model "as is", I fear your case is unsupported.
Either upgrade NHibernate, change your domain model, or change your querying API.