Introduction

I started using NHibernate at the end of last year and I am having a wonderful experience with it. The simple fact that I don't have to maintain hundreds of procedures and data access abstraction classes to do basic CRUD operations is enough to justify the use of NHibernate (even though I used a custom code generation tool). Besides that, my code is amazingly clearer and simpler. I only need to worry about business and user interface logic now. All that pluming code is gone for good.

I had zero experience with ORM frameworks, so on the first couple of weeks using NHibernate I had a hard time with some issues, like using it with ASP.NET disconnected objects and abstracting NHibernate sessions from the domain layer. After putting in some effort I came out with a nice architecture that abstracts the NHibernate layer and allows me to work with an ASP.NET session.

Background

I am assuming you already have some familiarity with NHibernate.
If you are new to NHibernate I encourage you to go to the website and download the reference documentation. I am using NHibernate 1.2 CR1 in this article.

The Architecture

The idea here is to keep my business objects unaware of an NHibernate session. So I created a different project for NHibernate stuff, called Shared.NHibernateDAL. It includes the session and transaction manager classes. I also created a common business object that serves as a base class for all my business entities. This class (BusinessObject) encapsulates the common methods and properties all entities that need to be persisted have, like Save(), Delete(), ID, etc.

Here's a class diagram just to give an idea:

The Implementation

The main classes on the NHibernateDAL project are the following:

NHibernateSessionManager – This is the class responsible for managing the NHibernate session. I've got this class from another NHibernate article on Code Project.

TransactionBlock – This is a class I created to manage transactions and abstract it from NHibernate. I will show an example of its use further on this article.

BusinessObject<T> - This is the base class for all the business entities I need to persist. It implements the basic CRUD methods.

Because all CRUD functionality is encapsulated on the BusinessObject, the domain entities are as simple as that. Now our Product class is ready to be consumed.

Note that I have included a static Select method that returns a list of products. This might be useful for populating user interface controls, but if you want to completely abstract NHibernate from your domain objects you should create another layer of abstraction under the business layer, containing all HQL queries. But, for small projects, I think it is OK to use HQL inside business objects.

The download file contains three projects, corresponding to the three layers I am using: NHibernateDAL, Business and Web. The Web project is a simple web page showing how easy it is to consume CRUD operations from the Product class.

Transactions

It is often necessary to use nested transactions with objects. You might have a method that opens its own transaction and sometimes needs to be called from another transaction.
To solve this problem and also abstract the NHibernate transaction methods I've come out with the TransactionBlock class. This class keeps track of how many transaction blocks were open and ensures that only one transaction is opened on the database. At the end it commits the transaction only if all blocks were declared valid.
Here's an example of its usage:

Conclusion

NHibernate has definitely helped me improve the quality and readability of my code. Combined with code generation tools (like MyGeneration), it can really improve productivity. But be aware, NHibernate and the architecture I am using will not fit every project. Working with legacy database can be a pain, although version 1.2 supports communication with stored procedures.

I guys I have been using LLBLGen and LLBLGen Pro so I am new to NHibernate and Active Record.
Actually I could not get the castle projects Mono to compile so I looked here. I think they need to update it.
Can you tell me where I can get this NHibernate database from that you are using? Or do I just create one in SQL and create a product table, then what goes into it?

Regards,
Alistair

Alistair Rigney
Software Engineer
Choose the appropriate technology before you do anything and check codeproject, sourceforge if someone has done it before.

On a different note, I just found your article and wanted to let you know that I liked your solution to the nested transaction problem. Providing the commit and rollback code in the dispose keeps the code a bit cleaner what with not needing the try catch and explicit begin, commit, rollback. Good job. We also implemented a transaction stack mechanism, but it relies on a more traditional try catch block.

To address the subject of this comment though, CallContext is not necessarily a safe place to put per thread values in a web environment. I'm not sure if that's what you're doing, but I figured I would pass this on as it caused us a bunch of problems in production. The problem is that a single web request is not guaranteed to live in a single thread context. I can't do the subject of context switching justice even if I took the time, but I'll drop a couple of links below.

Our solution was to check if HttpContext.Current != null. If it exists store items in HttpContext.Items, otherwise, use the CallContext: (sorry for the VB)

<System.Security.Permissions.SecurityPermission(System.Security.Permissions.SecurityAction.Demand,_flags:=System.Security.Permissions.SecurityPermissionFlag.Infrastructure)> _
Public NotInheritable Class ContextCache
Private Sub New()
End Sub
Public Shared Function GetData(ByVal key As String) As Object
If System.Web.HttpContext.Current IsNot Nothing Then
Return System.Web.HttpContext.Current.Items.Item(key)
Else
Return System.Runtime.Remoting.Messaging.CallContext.GetData(key)
End If
End Function
Public Shared Sub SetData(ByVal key As String, ByVal value As Object)
If System.Web.HttpContext.Current IsNot Nothing Then
If System.Web.HttpContext.Current.Items.Contains(key) Then
System.Web.HttpContext.Current.Items(key) = value
Else
System.Web.HttpContext.Current.Items.Add(key, value)
End If
Else
System.Runtime.Remoting.Messaging.CallContext.SetData(key, value)
End If
End Sub
End Class

You are correct. It's not the prettiest. On the plus side, since System.Web lives in the GAC, at least the assembly is not crufting up the bin directory of your desktop applications.

The primary service that we offer currently runs with a combination of the main web site, a second web site for our web API, three services and a newly added desktop application. This approach is working well for us.

If you're worried about the footprint of your windows applications, I suppose you could base the if statement off of a config value instead of HttpContext.Current != null, or use a factory method to create a wrapper for the two different approaches. That way System.Web would not be loaded unless you really were in a web app. Avoiding the reference didn't seem all that necessary to us though.

I personally, do not like the ActiveRecord approach to NHibernate. Because now you have created a depenedency between your business objects and nhibernate. In addition to this, All of your business classes MUST inherit from BusinessObject.

I place all of my Repository classes in a seperate assembly, and my Repository Interfaces within the core assembly. Then at runtime, Repository instances are injected into my domain layer. This eliminates the need for any nhibernate dependencies within my domain. It also eliminates the need for my business object from inheriting from a specific class.

Don't get me wrong, your method is MUCH better than plain old n-tier architecture, but I feel this method is flawed and creates tightly coupled architecture.

Now, if you want a quick and easy domain model that is persistable with NHibernate, you should check out Castle Projects' ActiveRecord project. It allows you to use attributes on your domain classes, and uses an ActiveRecord approach to the problem. This makes it much easier because you can do away with your nhibernate configuration file and let castle activerecord handle the problem instead. Here is a link to the project: The Castle Project.

Well written article though! I hope you take my comments as constructive criticism and not negatively =)

Sean, I agree with you. I too place my repository classes in a seperate library to avoid dependencies and I too use Castle's microkernel/windsor for IoC.

However, you have contradicted yourself. You said that using the base class (or other methods) creates a tightly coupled architecture with nHibernate... however, you also stated that using Castle's ActiveRecord was ok??? ActiveRecord relies on attributes that are tightly coupled with Castle.ActiveRecord, which in turn is tightly coupled with nHibernate.

I didn't say that using ActiveRecord was "ok", I was stating that if you DO want to use the ActiveRecord approach, then using Castle Projects ActiveRecord is a good option as it allows you to use attributes, you are correct in saying that this still tightly couples your domain model to nhibernate, just another option from your approach.

I have played with Castle's ActiveRecord but chose not to use it for the reasons that you stated. I didn't state that using Castle's ActiveRecord was better than your approach, its the same exact thing, just with a couple of other added benefits,(no nhibernate configuration file and attributes usage), but you still have the same side effects as your article.

I would agree with Sean's points as well. I think you're headed in the right direction, but that the tiers aren't separated enough if you're going for a data-access-agnostic domain layer. But, instead, if you're going for an Active Record[^] approach, then I would go all the way and embrace Castle Project's ActiveRecord[^] project. Furthermore, using Castle Project's ActiveRecord works hand-in-hand with Castle Project's Automated Transaction Management[^] which makes transaction management a much simpler task.

But in the context you presented, I very much liked your TransactionBlock. It seemed to make it easy to employ transactions only when needed within the specific context that it's applicable to. A drawback to my suggestions, described at http://www.codeproject.com/aspnet/NHibernateBestPractices.asp[^], is that a transaction is always applied to the entire HTTP request. To resolve it, I'm trying to create a custom transaction manager that extends from Castle Project's. We'll see how it goes.

Your article was well written and I look forward to seeing other articles from you in the future.

Sean, I can see your point when you say that my business objects are dependent on NHibernate. Although for the projects I am implementing right now, it is not a big deal. For some kinds of projects I prefer to create a dependency on something that probably will never change, than sacrifice simplicity, productivity or even performance. Plus, the business objects don´t have any code that is specific to NHibernate, so if we decide to use DLinq(?!) next year, I probably wouldn´t have to touch the objects (probably I would need to add DLinq attributes). Anyway, that´s just my point of view.

I would be glad to see the architecture you mentioned. Do you have it published?

I will take a look at the Castle Project, altough I like the idea of xml configuration files better than hardcoded attributes.

Billy, thanks for the compliment. Your article is very nice. It was of great help.

Maybe the links will help you. But the solution represented here is nice. My solution (the fix) is also similar, but it was checked also in multi-threaded enviroment (it already contains a small bugfix), so maybe it's worth checking it out.

I agree with Cassio that it depends on the project. I have used both approaches, (1) business Domain seperated from persistence layer which depends on NHibernate, and (2) ActiveRecord. I can say that ActiveRecord saves a ton of code, development time, testing etc. Of course, these savings could all be lost (and more) if you ever needed chuck NHibnerate or add some other persistence mechanism. So you need to ask yourself, based on business realities, how much am I (or my client) willing to invest now to ensure flexibility in the future? What's the likihood that this flexibility will ever be needed? And when asking this question keep in mind that a dollar today is worth a lot more than a dollar two or three years from now that might never even be spent. That said, many many cases will still indicate a more layered approach from the get go.

Thank you for the excellent intro article. I've been hoping somebody would write something like this! Hopefully my question isn't too technical for the intent of your article, but here goes--

Are Business Objects mapped 1::1 to the underlying persistent store table? Or, for example, can you have a business object that is the aggregate of several tables (think of an SQL view)? If so, how does NHibernate handle the relationships between the different tables, especially since the join types may not always be inner join? Would this require writing the SQL to "help" NHibernate in the query and subsequent updates?

People are just notoriously impossible. --DavidCrowThere's NO excuse for not commenting your code. -- John Simmons / outlaw programmerPeople who say that they will refactor their code later to make it "good" don't understand refactoring, nor the art and craft of programming. -- Josh Smith

I'm not the author of the article but I as I known (I'm not an expert...) you can't aggregate more than one table on the same business object.

I think that there are basically 4 class mapping features (that can also be combined):

1) 1::1 (the most common solution where each table is mapped to a class)
2) join associations: one-to-many, many-to-one, one-to-one (in this case you must declare an object for each table but then you can define what type of association exist between the objects). Typically used for collection mapping and parent-child relationship.
3) component (maps properties of a child object to columns of the table of a parent class). So for example you can write: Person.Address.City
4) inheritance mapping, to map a class hierarchy on the db:
-table per class hierarchy (or subclass mapping)
-table per subclass (or joined-subclass mapping)
-table per concrete class (I think not recommended)