Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is a static repository a right way to use NHibernate?

I spent the rest of the evening reading StackOverflow questions and also some blog entries and links about the subject. All of them turned out to be very helpful, but I still feel that they don't really answer my question.

So, I'm developing a simple web application. I'd like to create a reusable data access layer which I can later reuse in other solutions. 99% of these will be web applications. This seems to be a good excuse for me to learn NHibernate and some of the patterns around it.

My goals are the following:

  • I don't want the business logic layer to know ANYTHING about the inner workings of the database, nor NHibernate itself.
  • I want the business logic layer to have the least possible number of assumptions about the data access layer.
  • I want the data access layer as simplistic and easy-to-use as possible. This is going to be a simple project, so I don't want to overcomplicate anything.
  • I want the data access layer to be as non-intrusive as possible.

Will all this in mind, I decided to use the popular repository pattern. I read about this subject on this site and on various dev blogs, and I heard some stuff about the unit of work pattern.

I also looked around and checked out various implementations. (Including FubuMVC contrib, and SharpArchitecture, and stuff on some blogs.) I found out that most of these operate with the same principle: They create a "unit of work" which is instantiated when a repository is instantiated, they start a transaction, do stuff, and commit, and then start all over again. So, only one ISession per Repository and that's it. Then the client code needs to instantiate a repository, do stuff with it, and then dispose.

This usage pattern doesn't meet my need of being as simplistic as possible, so I began thinking about something else.

I found out that NHibernate already has something which makes custom "unit of work" implementations unnecessary, and that is the CurrentSessionContext class. If I configure the session context correctly, and do the clean up when necessary, I'm good to go.

So, I came up with this:

I have an internal static class called NHibernateHelper. Firstly, it has a static property called CurrentSessionFactory, which upon first call, instantiates a session factory and stores it in a static field. (One ISessionFactory per one AppDomain is good enough.) Then, more importantly, it has a CurrentSession static property, which checks if there is an ISession bound to the current session context, and if not, creates one, and binds it, and it returns with the ISession bound to the current session context.

Because it will be used mostly with WebSessionContext (so, one ISession per HttpRequest, although for the unit tests, I configured ThreadStaticSessionContext), it should work seamlessly. And after creating and binding an ISession, it hooks an event handler to the HttpContext.Current.ApplicationInstance.EndRequest event, which takes care of cleaning up the ISession after the request ends. (Of course, it only does this if it is really running in a web environment.)

So, with all this set up, the NHibernateHelper will always be able to return a valid ISession, so there is no need to instantiate a Repository instance for the "unit of work" to operate properly. Instead, the Repository is a static class which operates with the ISession from the NHibernateHelper.CurrentSession property, and exposes functionality through that by generic methods.

So, basically, I ended up with two very lazy singletons.

I'm curious, what do you think about this? Is it a valid way of thinking, or am I completely off track here?

EDIT:
I must point out that the NHibernateHelper class is internal, so pretty much invisible to the consumers of the repository.

Another idea is, in order to intoduce dependency injection into the solution, is to make an interface named IDataProvider, and instantiate one instance of that upon the first call to the Repository class. (However, the implementing code should be able to take care the concept of context also.)

EDIT 2:
It seems that many people like my idea, but there are still too few opinions about it in the answers.
Can I assume that this is a right way to use NHibernate, then? :P

like image 302
Venemo Avatar asked Apr 26 '10 22:04

Venemo


2 Answers

For what it is worth, Sharp Architecture is doing more or less exactly what you are suggesting. It ends up delivering one session per HTTP request (more accurately, one session per database per HTTP request). Your approach is certainly valid and also delivers one session per request. I rather prefer SharpArch's cleaner OO approach via DI over using static repositories and the helper class.

like image 96
Tom Cabanski Avatar answered Nov 01 '22 11:11

Tom Cabanski


We have mixed ASP.NET/Windows Forms applications and the best solution I've found is to do manual dependency injection through the repository constructor. That is, every repository class has a single public constructor that requires an ISession. This allows the application to have complete control over the unit-of-work and transaction boundaries. It's simple and effective. I also have a very small NHibernate helper assembly that configures the session factories and provides methods to open a regular or context session.

There are a lot of things I like about S#arp Architecture and I think that it's worth studying how it works, but I found it to be over-architected for my tastes.

like image 39
Jamie Ide Avatar answered Nov 01 '22 10:11

Jamie Ide