tags:

views:

136

answers:

2

We use one (read-only) session which we disconnect as soon as we retrieve the data from the database. The data retrieved, often has lazy-loaded properties which are not initialized yet.

When we try to access the properties, the following exception gets thrown:

NHibernate.LazyInitializationException

Initializing[NHibernateTest.AppUser#16]-failed to lazily initialize a collection of role: NHibernateTest.AppUser.Permissions, session is disconnected

Is there a way (interceptor) to automatically detect that the application is trying to access an uninitialized property, so that the interceptor can quickly open the connection and close it after the unit of work?

Fetching everything at once would nullify the usage of laziness.

+1  A: 

There is no efficient way to do that. The idea is that you keep the session open until your done with the session. There should be one session per unit of work. (a session is kind of unit of work actually).

Fetching everything your need in one query is more efficient than fetching everything you need in multiple queries, so I don't agree with your last statement. Lazy loading is useful for lazy programmers (like me) but is never more efficient than eager loading. Lazy loading can save you some programming time, but you still have to watch out for to many queries being executed (select N+1)

Paco
About your query count issue... You can mitigate this effect by using Batch loading in your persistence unit (so when you access a "child" of an instance of `Parent`, NHibernate gets up to ``BatchSize "child"ren for all "currently known" `Parent`s. I let your to the documentation for more about this.Also, Lazy Loading is more efficient in average than Eager when "most of time" you don't use the "lazy children" of a `Parent` entity. It's highly use-case dependent ultimately.
Romain
@Romain Muller: 1.) Batching can be used for several performance optimations, from which select n+1 is on of them. Another one is paging and I use it for more things, but batching does not prevent every select n+1, it will just convert "select n+1" into "select n/b + 1" most times.2.) Not loading is a different thing than lazy and eager loading. I don't mean to use eager in the mapping, I mean to use eager in the query.
Paco
@Paco, I'm not really into the discussion of whether or not to Lazy Load... I've already decided to go for it. My data-access layer gives me an object, which in 7 out of the 10 times, I just use as is. In 3 out of the 10 times, it needs to post-fetch some lazy properties. I do accept the performance bottleneck and I'm aware of N+1. This is the idea of lazy-loading in my sense (functionally). I guess what I'm asking here is just the technical implementation.
taoufik
@Paco, Futher... No, I don't want to keep my connection open, because I believe my connections are expensive to keep open only "in case of" and the session should take care of it. And I don't agree with you regarding "session == UoW", a session doesn't have to be short-running UoW, you can also have a long-running session, which you connect and disconnect whenever you want to perform an action. See for example, the samples in NH where they keep the session in a ASP.NET session.
taoufik
Keeping a session in an asp.net session can give you memory problems, because of the large amount of memory needed by the first level cache. Connections are managed by the session already, so there is no need to open/close connections manually. Your connectionpool won't be exhausted by keeping sessions open. "session == UoW" is not invented by me, but by the creators of NHibernate.
Paco
@Paco: in mean time I found out as well that the session actually does connection management. So, that helped me solve the exception. Thanks for highlighting that as well! Keeping sessions in asp.net might cause memory problems, given that there are many users logged in at the same time and l1 cache was used a lot. This was not true for my case, as my application is only used by a couple of users, and the session was used for only one scenario. Further, NH documentation also discusses long-running sessions, so a session is not automatically UoW. Thanks again! +1 for Paco.
taoufik
A: 

is there any solution to this problem? I have similar issues too...

Marko
The answer is in Paco's comment... you should leave ISession do the connection management. There is a property called 'connection release mode' which you can play with, but in a normal situation (and if you're not using System.Transactions), you shouldn't have to disconnect the ISession manually. It already does it internally.
taoufik