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:
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
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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With