dinsdag 1 juli 2008

NHibernate Session Management

I know that there has been written a lot about this topic, but somehow, I haven't found the 'sweet spot' concerning NHibernate Session Management in WinForms applications yet.

Some time ago, I've created a simple abstraction around the NHibernate ISession which would make it easier to use the ISession in my Winforms application.

Why do I want to clutter my presentation layer with NHibernate stuff, you ask ? Because Context is King.
The Repository has no notion of transactions, since the Repository doesn't know the context in where it's used.
Therefore, I like to start my Transaction in my WinForm app for instance, and pass the 'Transaction' to my repository, like this:



In the code above, the UnitOfWork class is just a simple wrapper around the NHibernate ISession which allows me to start and commit or rollback a transaction, disconnect the ISession from the Database, etc... with a minimum amount of code.

The UnitOfWork class looks like this:

This approach also allows me to have multiple NHibernate ISessions opened in one application instance.
This approach also gives me full control about when to start a new UnitOfWork, and when to close a UnitOfWork.

I've been convinced that this was the way to go. Especially because I thought that you had to commit the changes you've made to an object using the same ISession as the ISession which you've used to retrieve the object if you want to avoid unnecessary SELECT statements.

But, thanks to my collegue Thierry (who's starting to use NHibernate as well, and acted as some kind of catalysator to me so that I picked up my NHibernate quest again), it seems that my assumptions where not true:
I thought that, when you save an object to the datastore, using another ISession then the ISession you've used to retrieve the object, NHibernate would first perform a SELECT query in order to find out whether an INSERT or an UPDATE statement should be executed.
This seems to be false if you do not use the 'assigned' generator class for your Id property.

So, now I'm in doubt:


  • do I really need to be able to have concurrent ISessions in the same application instance ? Until now, I haven't needed it yet (so, yes, that makes it a YAGNI in fact).

  • I haven't seen anyone on the net using a similar approach. I see that everyone uses some kind of 'SessionManager' like the one Billy McCafferty has written here, so this makes me doubt as well ...

This last point is also the reason for this blogpost: I'm in doubt :)
Using some kind of 'SessionManager' class allows me to do the transaction demarcation where ever I want as well. Next to that, I also do not have to pass my UnitOfWork to the repository, since the repository has access to the current Session via the SessionManager as well ...

I know that, maybe, I should just give it a try. However, I'd like to hear experiences and thoughts of other people who are using (N)Hibernate in a Rich Client environment as well.
How are you dealing with those (session management) issues ? What difficulties did you encounter ?



Note: another post of me regarding this subject can be found here

assumptions are the mother of all fuckups.

3 opmerkingen:

Anoniem zei

Well,

It appears well defined that the "OpenSessionInViews" pattern is widely spreaded for ASP Application. It's ease the ISession management because it guarentee to you an Open Session from the begining of the HttpRequest trough the end where we close/commit... via an HttpModule. Crystal clear for Web Developpers...

With reach client you begin to worry about long living or short living session and this make you doubtful over which strategy to use and how to manage your session.

After thinking around for a couple of hours. I minded that every way, what I find interresting with the Billy McCafferty's approach is the fact that you don't worry about an opened or closed session. Just issue a trans = SessionManager.BeginTransaction where and when you want, the SessionManager check for you about a current ISession and a current ITransaction...

It also mean that you can also call CommitTransaction and CloseSession as often as you want leading to short living session without the need to worry about.

As you mention, when should you have concurent ISession on a database?

I must also admit that it is also more easier if you used id generator but if you analyze some code Billy McCafferty provides, he also has a solution to deal with assigned id when you have to deal with legacy database.

So far I readed and re-readed the NHibernate user guide, use of assigned id is not encouraged.

It's just my humble opinion.

I prefer a bottle in front of me than a frontal lobotomy.

Thierry.

Rémy zei

If you want some more inspiration, look at the code of Ayende, one of the developers of NHibernate. He has a library Rhin.Commons, which contains some interesting thoughts about this subject. See Rhino Commons, Repository and Unit Of Work.You can get the code from his svn repository: https://rhino-tools.svn.sourceforge.net/svnroot/rhino-tools/trunk

Frederik Gheysels zei

Thanks for the tip Rémy. :)
Although I'm aware of Ayende and his work (his blog is in my RSS reader), I'll surely review Rhino.Commons (I already downloaded it a few weeks ago, but I didn't really dive into the code yet).