When I first researched the usage of
NHibernate in a Winforms environment, I was rather disappointed to find out there's very few (to none) articles that discuss the subject in a general sense or introduce it to beginners (like me). This is why I've decided to summarise most of my findings into one article, providing a sort of a framework with which developers, who are new to NHibernate and are about to work with it in a Winforms environment, could find a starting point.
While this article does not pretend in any way to provide a set of best practices, I would be very happy to get any constructive feedback that may contribute and create eventually a sort of a Winforms parallel to Billy McCafferty's NHibernate Best Practices For ASP.NET.
Before reading this article, I would suggest anyone who may not be familiar with the term "Dependency Injection" (DI) to read either McCafferty's article on DI, or Oren Eini's brilliant take on the subject.
You will also need the Spring.Net framework (although any other container would do. I chose to work with spring for this example) and the SmartCode code generation tool.
Using the Code
Now, when beginning to work with
NHibernate in Winforms, you'd probably see first of all that the main difference between Winforms and a web environment is the way you deal with your sessions. While working with the web, the sessions are opened and closed per Requests normally. This however proves to be more complicated in Winforms, since you don't have requests, and leaving a session open per window might end in an extremely heavy session cache, simply because a window might stay open and 'alive' for a much longer period than an ASP.NET request. In multiuser applications, this might also increase the possibility of getting
The solution that seems to be the most appropriate is fairly documented in the Spring forums. However, this may lead to another problem of lazy loading mode, as a session will not be open whenever you would like to lazy load a collection. To this problem, unfortunately, there is no one straight answer, simply because each case should be considered apart. More on that could be found also on the spring forum, or in another article of mine, Lazy Initializer for NHibernate.
Session management would therefore become less chaotic when working with spring's transaction attributes and
TransactionManager. All you need to do is simply add the attribute on the service method that'll call the data access layer (DAL) like so:
public virtual void AccessMyDB()
When working in the DAL with Springs'
HibernateTemplate, this will allow spring to create a new session or fetch an already existing open session whenever needed (also, when catching an exception, the transaction will rollback by default. The transactions can also be globally parameterised in the spring XML configuration section).
Working with the
HibernateTemplate becomes even more easy with the
HibernateDaoSupport parent class the folks in spring created for us. What I've done was simply created a base dao all my daos inherit, while the base dao inherits from the
HibernateDaoSupport. You may find more information on the
HibernateDaoSupport in the spring documentation.
This approach (allocating a transaction / session per service method) will reduce the probability of handling a
StaleObjectStateException in multiuser applications. When working on applications where it's unlikely two users will modify the same entity/ies at the same time, you could use a different approach where the life of a session can span a number of service methods (some more on that could be found on Gustavo Ringles blog- and thanks to Daniel M. Camenzind for sharing).
As for the 'higher' layers- the user interface and the model-view layer, I found the MVP pattern to be the most elegant and suitable solution for a better separation between the service and the user interface layers. With the MVP pattern, no service code will be found directly in the user interface, but in the 'presentation' layer. This will then allow the insertion of a whole new user interface layer (if for example, you'd like one day to move from Winforms to XAML).
More on the Model-View-Presenter pattern could be found in Mike Peretz article on MVP using DI.
Generating the Framework
Now, to facilitate the creation of such a framework, I have re-written and extended the base template found in the SmartCode code generation tool. Why SmartCode of all the codegen tools out there that do a good job with NHibernate? Well, in my opinion SmartCode does the job pretty well, delivers a code that is fairly minimal (which was the best solution for my case) and highly modifiable. Also, the templates are all written in C# which was a plus for me. If you'd like to change the templates to suit you better, you'd see that it won't take too long to get the hang of it. Here is a good article on how to work with SmartCode (by its creator); you could start reading it from the 'SmartCode Projects' section.
You may download the templates from the link on the top of the page.
All you'll need to do now is simply create a new solution and add the following projects to it:
and your UI (
MySolution.UI if you'd like...)
You should then add a reference to your Core project in all of the other projects. A reference to NHibernate should be added as well to the Core and Data projects. The Data Project should have references to the
Spring.Services DLLs. The Service project should reference the
After generating the code, simply drag and drop the code generated in the folder you've selected: all the subfolders of the Core folder to your Core project, Data subfolder to Data project etc. The contents of the app.config.xml file should be copied into your app.config file. This will contain your spring configurations.
An example of the code I've generated for the Northwind database could be found here (a zip of 7.1 MB, since it's the whole solution, which is also why I didn't attach it to the article directly). The only thing I've added was the
Form1 implementation of the
LoadEmployeeById event to the
IEmployeeView, and the
LoadEmployeeById event handler in the
If you feel something is missing in the template, let me know and I'll do my best to add it.
The patterns I've chosen to work with are by no means the best practices to working with
NHibernate in Winforms. This article serves only to condense all that I've learned and the material I found on the subject. Even my experience with working with these tools is unfortunately limited. What I did was simply summarise other people's experiences to one place. If you'd like to add anything or you've written a similar article on the subject, feel free to let me know.