views:

770

answers:

5

I'm new to NHibernate, and have seen some issues when closing sessions prematurely. I've solved this temporarily by reusing sessions instead of opening a session pr transaction. However, I was under the impression that opening sessions each time you need them was the recommended approach for session lifetime management. No?

So; what is the recommended way of handling sessions? What should their lifetime be? One session pr transaction? One singleton session to handle everything? Or what?

Edit:

Note that my application architecture is a desktop application communicating with a server side service, which is what does all the Database handling, using NHibernate + Fluent. (If this makes any difference...)

+4  A: 

A session should correspond to a unit of work. The session should stay alive while you are working with the objects retrieved or persisted using that session.

David M
+2  A: 

There isn't one answer that fits all situations. Session 13 of Summer of Nhibernate presents a nice overview of the issue.

kgiannakakis
A: 

Much of the NHibernate framework and Microsoft ADO.NET Entity Framework are similar. Here is a very good article about how you should control an ObjectContext lifeline in the ADO.NET EF.

http://blogs.msdn.com/alexj/archive/2009/05/07/tip-18-how-to-decide-on-a-lifetime-for-your-objectcontext.aspx

It should apply to NHibernate sessions as well.

David Pfeffer
In my opinion, since EF 1.0/3.5 doesn't support automatic proxy based lazy loading, the differences between EF and NHibernate in regards to this issue are too large to effectively share advice. ObjectContext lifetime in EF is simpler to manage because EF isn't as feature rich.
Michael Maddox
You are correct that EF 1.0 does not support that, but EF 2.0 does. This article seems to apply to both.
David Pfeffer
+5  A: 

In a web app, you should have one session per request. This gives you full control over the session lifetime and simplifies error handling.

In a desktop app, I recommend using a session per presenter (or form if you prefer). To quote Ayende in his MSDN Magazine article:

The recommended practice for desktop applications is to use a session per form, so that each form in the application has its own session. Each form usually represents a distinct piece of work that the user would like to perform, so matching session lifetime to the form lifetime works quite well in practice. The added benefit is that you no longer have a problem with memory leaks, because when you close a form in the application, you also dispose of the session. This would make all the entities that were loaded by the session eligible for reclamation by the garbage collector (GC).

There are additional reasons for preferring a single session per form. You can take advantage of NHibernate’s change tracking, so it will flush all changes to the database when you commit the transaction. It also creates an isolation barrier between the different forms, so you can commit changes to a single entity without worrying about changes to other entities that are shown on other forms.

Martinho Fernandes
"session per operation" is rather vague. You should mention "session per request"
Mauricio Scheffer
+7  A: 

You want a session management strategy that allows your app to function effectively and take advantage of the things that NHibernate gives you - most notably caching and lazy loading.

Creating sessions is an inexpensive process and requires little up-front RAM or CPU, so you shouldn't worry about conserving or re-using sessions (indeed, re-using them can lead to some nasty and un-anticipated side-effects). The session factory is the expensive thing and should be built once and only once at app startup.

The rule of thumb is this: the session lifetime needs to be long enough that you don't have persisted objects hanging around in scope after the session ends.

Once the session ends, all change tracking for objects you got from that session stops, so those changes don't get saved unless you deliberately re-attach that object to a new session. The session should therefore be around for as long as the objects you fetch from it are going to exist. In a Web app, that generally means a session for each request; in WinForms, a session for each form.

In your case, with a service (I assume it's running as a Windows service) doing the NHibernate work, you might wish to consider having a session created for each new request from the consuming desktop app, and disposing it when that request has been serviced. Not knowing exactly how your service runs and what mechanism the desktop app uses to talk to it (remoting? WCF? Plain old SOAP?) I can't really be more specific.

(There are some exceptions to this general rule - suppose you have a set of persisted objects that represent a shared resource to which other code will refer but not change, you can load these up-front at app-start and leave them disconnected from then on.)

If you find performance sluggish under such a strategy, it may be that you're just talking to the database too much and your object graph is complex; look at second-level caching in this case.

DotNetGuy
Thanks! Regarding my service I'm using WCF, currently with soap - running as a console application, but I don't think this should make any difference, so you were specific enough. Sounds reasonable to have one session for each request. Currently I'm only using a session where the transaction is being run, and there seems to be some referenced data which is not loaded during the transaction which fails because the session is closed.
stiank81