Title:       An All-inclusive Data Access Layer for NHibernate
Author:      Antoine Jaussoin
Email:       a.jaussoin@laposte.net
Member ID:   1461364
Language:    C#
Platform:    Windows
Technology:  NHibernate, C#, ASP.NET, .NET
Level:       Intermediate
Description: A Domain Driven architecture using NHibernate for an easy to use Data Access Layer
Section      Type the Code Project Section you Wish the Article to Appear
SubSection   Type the Code Project SubSection you Wish the Article to Appear
License:     CPOL

Introduction

Writing a clean Data Access Layer (DAL) is often a tricky thing to do.
Most of the time you end up with a DAL that is bleeding into your UI, and you don't (or can't) keep the separation of concern between your UI, the Business Layer (the logic of your application), and your DAL.
This article (and this project) is aimed to help you achieve a pure separation between these layers, using techniques and frameworks such as:

It is also very important to mention that this framework is completely independent from NHibernate. The only implementation of the DAO/Repository layer is using NHibernate at the moment, but nothing prevents you from implementing this using something else.

Where to download

Your best shot is the CodePlex website.
You can either download the latest release, or even the trunk.
The address is: CodePlex

Background

This project (FT.Architecture) started as a project aimed at creating NHibernate-powered ASP.NET controls.
When developing this, it deviated into the creation of a full framework, and now the NHibernate-powered controls are just a small part of it.

Code Snippets: what the framework will provide

Everything in this framework works around a concept: the Unit of Work.
A Unit of Work (as explained by Martin Fowler here: http://martinfowler.com/eaaCatalog/unitOfWork.html)

Maintains a list of objects affected by a business transaction and coordinates the writing out of changes and the resolution of concurrency problems

In other word, everything that happens inside a UoW is transactional (very much like a database transaction). Actually, the UoW described here is a wrapper around NHibernate's ISession, which is a wrapper around a database transaction.

Let's see that in pratice.

Important: this is only a tiny slice of what the framework provide, you'll need to download it and try it to see all the other methods.

Basic stuff: Get by ID

[csharp] using (var t = DAL.GetUnitOfWork()) { IHuman human = t.GetRepository().GetById(123); System.Console.Out.WriteLine(human.Name); t.Commit(); } [/csharp] As you can see above, no SQL code or NHibernate code has been written! Actually, the client code that uses this doesn't have any reference to either NHibernate, ADO.NET, or anything like that.
The generic Repository we get contains many more methods such as GetAll, GetByMember, GetCount, GetRandom, etc.
Most of the time you won't have to code a single query to get objects from the database, ready to use.

Get By Member (recursive!)

[csharp] using (var t = DAL.GetUnitOfWork()) { IList humans = t.GetRepository().GetAllByMember(x => x.Father.Father.Name, "Anthony"); t.Commit(); } [/csharp] This will, effortlessly, return all the IHuman objects whose grand-father was named "Anthony"! And that, for free!
You'll also notice that the "Father.Father.Name" property was not passed as a (fragile) string, but rather by a lambda expression, which supports compile-time checking and easy refactoring!

Linq Provider

[csharp] using (var t = DAL.GetUnitOfWork()) { var humans = from IHuman h in t.GetRepository().GetLinq() where h.Name.StartsWith("Ant") select h; t.Commit(); } [/csharp] As you can see, using Linq is very easy! Just call the GetLinq() method on the repository of your choice, and it will return an IQueryable collection you can interfere with. This will generate (thanks to Linq of NHibernate) the needed SQL.

ASP.NET: Base Page and Base Control facilities

Unit of Work for free

Provided you are using the NHibernateUnitOfWorkHttpModule as a HttpModule in your web application, and provided you make your page and control inherit from the relevant BasePage and BaseControl, you'll have an open Unit of Work directly from your page!
You can then write code like this within your code behind: [csharp] protected void Page_Load(object sender, EventArgs e) { //That gives you a random IHuman entity for free IHuman human = UnitOfWork.GetRepository().GetRandom(); } [/csharp] As you can see, no need to open a transaction, or a database connection, or anything... it just works out of the box, and your entire DAL is there for free.

Storing entities across postbacks

As you probably know, the main problem with HTTP is that this protocol is stateless. It means you have to invent mechanism (such as ViewState, Session, etc.) to store data across each postback.
Storing an entity is not easy, as you don't want to store the entire object-tree on the viewstate! This would make the page way too big...
It's where GetEntity and SetEntity comes to the rescue: you can store an entity transparently across postbacks, and the only things that will actually be stored into the ViewState is the entity ID! (along with its type).
That will have a very small memory footprint, and it will be very efficient.
This is how it works: [csharp] //Stores an entity public IHuman SelectedHuman { get { return GetEntity("human"); } set { SetEntity("human", value); } } //Stores a simple field (serialised) public string StoredString { get { return GetField("myString","default-value"); } set { SetField(value, "myString"); } } [/csharp] There's also a facility to store collections of entities (SetEntities and GetEntities).

The Architecture

Separation of concerns

Various Libraries

As you can see in the schema above, we achieve here a full separation of concerns:

The different libraries

FT.Architecture layers

Here is a detailed explanation of what each library (or package does):

All right: I want to play with it!

The archive provided will allow you to play with it out of the box, as long as you complete these few steps:

  1. Install SQL Server (Full or Express), 2005 or 2008, and the Management Studio
  2. Open Management Studio, and create a new database called "ncontrols"
  3. Download (http://ncontrols.codeplex.com/) and unzip the archive
  4. Open the solution, compile and run the WinForm project
  5. Go on the "Database Setup" tab
  6. Click on "Create Database", which should create the tables, and fill the database with dummy data, so you can play with it
  7. (bonus: if you run the unit tests, make sure you also created another database called "ncontrolstwo")
Pretty simple uh?
(note: if you have SQL Server (not Express), you might need to change the connection string on the nhibernate.config file on the project you are trying to run).

Copyrights

Part of my code uses someone elses code, which are:

If I forgot to mention someone, please advise and I'll be happy to correct that!

History