Introduction
Martin Fowler writes:
"When you're pulling data in and out of a database, it's important to keep track of what you've changed; otherwise, that data won't be written back into the database. Similarly you have to insert new objects you create and remove any objects you delete."
and
"A Unit of Work keeps track of everything you do during a business transaction that can affect the database. When you're done, it figures out everything that needs to be done to alter the database as a result of your work."
In NHibernate we have the Session object which is a Unit of Work (UoW) container. The session object keeps track of all objects you load, new objects you add, existing objects you delete and changes you make to any of these objects. Only when flushing the session will the database be altered (that is: will the necessary create, update and delete statements be sent to the database).
Now, working directly with the NHibernate session object makes absolute sense. But some times you rather want to abstract the data manipulation interface from a specific infrastructure implementation à la NHibernate.
Note: most of the design ideas and implementation details presented here originate from Ayende's UnitOfWork implemented in the Rhino.Commons which you can get here.
Design and Implementation (TDD)
Some thought about TDD
I want to implement a UnitOfWork pattern for NHibernate and I want to do it by using TDD. For a beginner (like I was myself not so long ago) it seems unnatural at the beginning. We introduce a huge overhead you might think. You might also think that we have to write at least double the code as when doing the development without TDD. But wait until you have to start to debug your application... or until the customer wants to have something changed in the application... or until you have to re-factor you application... Then you will immediately see and feel the benefits of a good test coverage.
Attention: Multi-Threading ahead
Please not that the implementation presented here is strictly NOT thread safe!!! I want to reduce the complexity of this first implementation. But I promise that in a following post I'll show you how to make the implementation of the unit of work pattern thread safe and thus useful for e.g. Web scenarios.
The UnitOfWork Class
To start with: I want to have an easy way to start a new UoW, in any place of my application have access to the current UoW and commit the business transaction represented by my UoW. We can do this with a static class called UnitOfWork
The method start creates and returns an instance of a UnitOfWorkImplementor class which implements the interface IUnitOfWork. As you can see then interface IUnitOfWork inherits from IDisposable. So we can define that the business transaction is ended when the UoW is disposed. Now, if we do nothing else then nothing should happen, that is no changes should be propagated to the database. To commit a business transaction we have to explicitly call a method of the UoW. Let's call this method TransactionalFlush. In doing so all changes recorded by the UoW are committed to the database in one go.
Now let's start to implement this! We are doing TDD, aren't we? So we will write our first test (if you are not sure how to best setup a new solution for TDD please consult this post). I define a new solution with two projects as follows
Add a class UnitOfWork_Fixture.cs to the test project and implement the first test like this
[TestFixture]
public class UnitOfWork_Fixture
{
private readonly MockRepository _mocks = new MockRepository();
[Test]
public void Can_Start_UnitOfWork()
{
IUnitOfWork uow = UnitOfWork.Start();
}
}
Of course this test will not compile since you don't have the types UnitOfWork and IUnitOfWork defined yet. Let Resharper create them for you (or implement them by hand)
public static class UnitOfWork
{
public static IUnitOfWork Start()
{
throw new NotImplementedException();
}
public static IUnitOfWork Current { get; private set; }
}
public interface IUnitOfWork : IDisposable
{
}
Now the test will compile but it will fail! Of course, you haven't implemented the Start method so far. In this method we must now create a new UoW and return it to the caller. A UoW is a complex beast and should therefore be constructed in a factory. So let's define a factory Interface IUnitOfWorkFactory with a method Create which returns a UoW implementing the interface IUnitOfWork.
public interface IUnitOfWorkFactory
{
IUnitOfWork Create();
}
since we want to test our UnitOfWork class in isolation we have to mock all other dependencies line the unit of work factory. I'll use Rhino.Mocks as my mocking framework (Please refer to documentation here). I want to test that when calling the start method of the UnitOfWork class the factory gets called. So I extend my test function
[Test]
public void Can_Start_UnitOfWork()
{
var factory = _mocks.DynamicMock<IUnitOfWorkFactory>();
var unitOfWork = _mocks.DynamicMock<IUnitOfWork>();
// brute force attack to set my own factory via reflection
var fieldInfo = typeof(UnitOfWork).GetField("_unitOfWorkFactory",
BindingFlags.Static | BindingFlags.SetField | BindingFlags.NonPublic);
fieldInfo.SetValue(null, factory);
using(_mocks.Record())
{
Expect.Call(factory.Create()).Return(unitOfWork);
}
using(_mocks.Playback())
{
var uow = UnitOfWork.Start();
}
}
In the first two lines of code I mock the external dependencies of the UnitOfWork class. Then I do something you should not do very often (but I have good reasons doing so here and I promise it's the only time I'll do it in this project...). I set a private field of the UnitOfWork class with a value by using reflection. I could implement a public setter in the class but as I would only need it for this test and I want to keep the class interface as simple as possible I chose to do it via reflection.
In the record phase I define my expectation (namely that the factory create method is called) and in the playback phase I invoke the Start method which I want to test. The test will compile but fail to execute. I have not yet defined the private static field _unitOfWorkFactory and I also do not call the factory. So let's modify our code...
public static class UnitOfWork
{
private static IUnitOfWorkFactory _unitOfWorkFactory;
private static IUnitOfWork _innerUnitOfWork;
public static IUnitOfWork Start()
{
_innerUnitOfWork = _unitOfWorkFactory.Create();
return _innerUnitOfWork;
}
public static IUnitOfWork Current { get; private set; }
}
now the test will pass.
Since in all our test regarding the UnitOfWork class we will always need it with an injected factory we define a new test fixture with a context setup for our specific needs. We put the respective code in the SetupContext and TearDownContext methods
[TestFixture]
public class UnitOfWork_With_Factory_Fixture
{
private readonly MockRepository _mocks = new MockRepository();
private IUnitOfWorkFactory _factory;
private IUnitOfWork _unitOfWork;
[SetUp]
public void SetupContext()
{
_factory = _mocks.DynamicMock<IUnitOfWorkFactory>();
_unitOfWork = _mocks.DynamicMock<IUnitOfWork>();
// brute force attack to set my own factory via reflection
var fieldInfo = typeof(UnitOfWork).GetField("_unitOfWorkFactory",
BindingFlags.Static | BindingFlags.SetField | BindingFlags.NonPublic);
fieldInfo.SetValue(null, _factory);
_mocks.BackToRecordAll();
SetupResult.For(_factory.Create()).Return(_unitOfWork);
_mocks.ReplayAll();
}
[TearDown]
public void TearDownContext()
{
_mocks.VerifyAll();
}
}
Note: in the second last line of the SetupContext method we define that each time the method Create of the factory object is called (by the UnitOfWork Start method) we want it to return our predefined mocked _unitOfWork instance.
Trying to start a UoW if there is already one active should throw a meaningful exception. This is the test
[Test]
public void Starting_UnitOfWork_if_already_started_throws()
{
UnitOfWork.Start();
try
{
UnitOfWork.Start();
}
catch (InvalidOperationException ex)
{ }
}
As a consequence we have to extend our Start method in the UnitOfWork class
public static IUnitOfWork Start()
{
if (_innerUnitOfWork != null)
throw new InvalidOperationException("You cannot start more than one unit of work at the same time.");
_innerUnitOfWork = _unitOfWorkFactory.Create();
return _innerUnitOfWork;
}
Now I have another problem: After the test is finished the static field _innerUnitOfWork of my UnitOfWork class is set to a value other than null. This will have a undesired side effect to the following test. I have to reset this field. Again in this special case I'll do it via reflection to not clutter the interface of my class (static classes are difficult more complex to deal with in TDD than non static classes...). We do reset our UnitOfWork class in the TearDownContext method
[TearDown]
public void TearDownContext()
{
_mocks.VerifyAll();
// assert that the UnitOfWork is reset
var fieldInfo = typeof(UnitOfWork).GetField("_innerUnitOfWork",
BindingFlags.Static | BindingFlags.SetField | BindingFlags.NonPublic);
fieldInfo.SetValue(null, null);
}
Next we want to be able to access the current unit of work. As usual we first implement a test
[Test]
public void Can_access_current_unit_of_work()
{
IUnitOfWork uow = UnitOfWork.Start();
var current = UnitOfWork.Current;
Assert.AreSame(uow, current);
}
You can figure out what code you need to implement for the test to pass.
We also want to assert that when accessing the current UoW if no UoW has been started that a meaningful exception is thrown
[Test]
public void Accessing_Current_UnitOfWork_if_not_started_throws()
{
try
{
var current = UnitOfWork.Current;
}
catch (InvalidOperationException ex)
{ }
}
now my implementation of the Current property in the UnitOfWork class is as follows
public static IUnitOfWork Current
{
get
{
if (_innerUnitOfWork == null)
throw new InvalidOperationException("You are not in a unit of work.");
return _innerUnitOfWork;
}
}
Next we want a property on the class which tells us whether a UoW is started or not. The test for it
[Test]
public void Can_test_if_UnitOfWork_Is_Started()
{
Assert.IsFalse(UnitOfWork.IsStarted);
IUnitOfWork uow = UnitOfWork.Start();
Assert.IsTrue(UnitOfWork.IsStarted);
}
It's getting boring isn't it... But this is the way TDD works. You always think (hard) on what you need and then you implement the test with which you can proof that you get it as you want it. Only then you implement the functionality needed to fulfill the test. If you do so you automatically follow the YAGNI principle (you ain't gona need it) that is you only implement the code you really need!
We can fulfill the test like so
public static bool IsStarted
{
get { return _innerUnitOfWork != null; }
}
The UnitOfWork class is now a perfect wrapper for the NHibernate session object. Though for some advance scenarios I would like to have access to the session object related to my UoW. As a consequence I'll implement a read only property CurrentSession in the UnitOfWork class. Lets again start with the test
[Test]
public void Can_get_valid_current_session_if_UoW_is_started()
{
using (UnitOfWork.Start())
{
ISession session = UnitOfWork.CurrentSession;
Assert.IsNotNull(session);
}
}
and the implementation
public static ISession CurrentSession
{
get { return _unitOfWorkFactory.CurrentSession; }
internal set { _unitOfWorkFactory.CurrentSession = value; }
}
Note that I have just delegated the call to the factory class. Thus to make the test pass I have to add two additional lines to the SetupContext method of the test fixture where I mock a session object and setup the result for a call to the property CurrentSession of the factory.
[SetUp]
public void SetupContext()
{
_factory = _mocks.DynamicMock<IUnitOfWorkFactory>();
_unitOfWork = _mocks.DynamicMock<IUnitOfWork>();
_session = _mocks.DynamicMock<ISession>();
// brute force attack to set my own factory via reflection
var fieldInfo = typeof(UnitOfWork).GetField("_unitOfWorkFactory",
BindingFlags.Static | BindingFlags.SetField | BindingFlags.NonPublic);
fieldInfo.SetValue(null, _factory);
_mocks.BackToRecordAll();
SetupResult.For(_factory.Create()).Return(_unitOfWork);
SetupResult.For(_factory.CurrentSession).Return(_session);
_mocks.ReplayAll();
}
That's all we need for the moment regarding the UnitOfWork class. Next topics will be the the implementation of the UnitOfWorkFactory class and then of the UnitOfWorkImplementor class. The details will be presented in the next post to this blog. So keep ready...
Code Repository
We have prepared a code repository on Google code dedicated to this blog. If you want you can download the whole project from here and play with it. Note that this is a Visual Studio 2008 type solution and is based on C# 3.0.
Any comments are really welcome!
Enjoy
.