Monday 7 March 2011

Nhibernate, Unit Of Work, Repository and StructureMap

This could be a long blog...

Well I have spent some time recently trying to understand how to tie all this lot together and I think I have finally cracked it in its simplest form, I am hoping at least. This is my first stab at it and I am already thinking of changing it slightly, but I want to show what I did first.
If there is anything you don't like on here or want to question please come and comment as I would love to get some feedback on what people thought of this. Problematic, see problems with it or even helped to understand it better.

NHibernate
So first of all I modelled a simple domain, just an account user and mapped this to NHibernate to do its thing with the db. Understood then that the NHibernate's SessionFactory should be once per application as its very expensive to create and that ISession is what to use every time you want to make a single or group of changes to the db, or to just retrieve anything.

Code that I Wanted/Needed
So the following are the general things I used and set up simply as possible for now.

Repository
First off I read up loads of articles on creating a repository to wrap up simple NHibernate commands. This could be extended in the future to provide a more advanced implementation. Some would argue not to have the repository at all and use the NHibernate calls directly. I like the idea of keeping the repository implementation as I am hoping it decouples NHibernate from the application (don't know why I will ever need to not use NHibernate yet but its there). I would like to be able to create as many of these as I would like although at the moment I am unsure why I would need more than 1 per thread. This will contain a UnitOfWork.

    5     class Repository : IRepository
    6     {
    7         readonly IUnitOfWork _unitOfWork;
    8 
    9         public Repository(IUnitOfWork unitOfWork)
   10         {
   11             _unitOfWork = unitOfWork;
   12         }
   13 
   14         #region IRepository<AccountUser> Members
   15 
   16         public T GetById<T>(Guid id)
   17         {
   18             return _unitOfWork.CurrentSession.Get<T>(id);
   19         }
   20 
   21         public void Add<T>(T entity)
   22         {
   23             _unitOfWork.CurrentSession.SaveOrUpdate(entity);
   24         }
   25 
   26         public void Remove<T>(T entity)
   27         {
   28             _unitOfWork.CurrentSession.Delete(entity);
   29         }
   30 
   31         #endregion
   32     }


UnitOfWork
This implements IDisposable and is what I used to manage the transaction of the NHibernate session. I would like it to dispose of the session once its been commited or rolledback, it just has a simple commit and rollback and manages to close the session. The session and transaction is created in the constructor here, so the UnitOfWork is ready to be commited or rolledback. The more I am typing here the more I am feeling this class is clunky around the edges of cleaning up. I am not sure if I need to rollback the transaction by default in the dispose if its active already, or whether the Session manages maintains that on a dispose of itself? If anyone knows let me know :-)

    6     public class UnitOfWork : IUnitOfWork
    7     {
    8         private readonly ISessionFactory _sessionFactory;
    9         private ISession _currentSession;
   10         private readonly ITransaction _currentTransaction;
   11 
   12         public UnitOfWork(ISessionFactory sessionFactory)
   13         {
   14             _sessionFactory = sessionFactory;
   15             _currentTransaction = CurrentSession.BeginTransaction();
   16         }
   17 
   18         #region IUnitOfWork Members
   19 
   20         public ISession CurrentSession
   21         {
   22             get { return _currentSession ?? (_currentSession = _sessionFactory.OpenSession()); }
   23         }
   24 
   25         protected ITransaction BeginTransaction()
   26         {
   27             return _currentSession.BeginTransaction();
   28         }
   29 
   30         public void Commit()
   31         {
   32             if (_currentTransaction.IsActive)
   33                 _currentTransaction.Commit();
   34         }
   35         public void Rollback()
   36         {
   37             if (_currentTransaction.IsActive)
   38                 _currentTransaction.Rollback();
   39         }
   40 
   41         #endregion
   42 
   43         #region IDisposable Members
   44 
   45         public void Dispose()
   46         {
   47             if (_currentSession == null) return;
   48 
   49             _currentSession.Dispose();
   50             _currentSession = null;
   51         }
   52 
   53         #endregion
   54     }

As you can probably see there is no creation of the interfaces SessionFactory or UnitOfWork in repository and this is where I have used StructureMap to help out.

StructureMap
I went the Ninject route initially as it had a cool looking site and seemed quite nice to use also. I managed to achieve what I wanted with it and it wasn't difficult at all but I wont show that here. I researched further into which DI/IOC to use and I kind of had a good feel for what people were saying about StructureMap so I changed to use StructureMap instead.
OK so I figured I needed
  • 1 SessionFactory per application running.
  • 1 UnitOfWork per thread running.
  • No limit to the number of Repositories. (not sure why this can't be 1 instance per thread also but I don't think there is harm in having more than 1 as it will use the same UnitOfWork if its in the same thread.)
    9    public static class ContainerBootstrapper
   10     {
   11         public static void BootstrapStructureMap()
   12         {
   13             ObjectFactory.Initialize(x =>
   14             {
   15                 x.ForSingletonOf<ISessionFactory>().UseSpecial(y =>
   16                     y.ConstructedBy(context =>
   17                     {
   18                         var nhConfig = Fluently
   19                          .Configure()
   20                          .Database(MsSqlConfiguration
   21                                     .MsSql2008
   22                                     .ConnectionString(connstr =>
   23                                         connstr.FromConnectionStringWithKey("db")))
   24                          .Mappings(mappings => mappings
   25                                                 .FluentMappings
   26                                                 .AddFromAssemblyOf<AccountUser>())
   27                          .BuildConfiguration();
   28 
   29                         return nhConfig.BuildSessionFactory();
   30                     }));
   31                 x.For<IUnitOfWork>().HybridHttpOrThreadLocalScoped().Use<UnitOfWork>();
   32                 x.For<IRepository>().Use<Repository>();
   33             });
   34         }
   35     }
So in here, I am setting up the
  • 1 single SessionFactory ever for the application. The x.ForSingletonOf<ISessionFactory> will sort this out. It uses the Fluent style configuration of the sessionFactory using the database connection and mappings from the domain model set up.
  • Per thread UnitOfWork, we want this as we may have more than 1 save, update and delete on the same transaction, so when its injected into the repository its the same UnitOfWork that is used before the repository has begun to be used, I will show a test later on with this.
  • Repository.
A Couple of Tests
I will try and show a couple of tests that I set up for this, and show how it could be used from the outside. I hope my tests aren't too bad, I know I find it difficult to write a good test, come slate them let me know what you would do, naming them something different? anything? I need to learn more about tests.

Test to write data to the database was successful.
   67         [TestMethod]
   68         public void Can_SaveSomeUserDataViaStructureMap()
   69         {
   70             ContainerBootstrapper.BootstrapStructureMap();
   71 
   72             using (var uoW = ObjectFactory.GetInstance<IUnitOfWork>())
   73             {
   74                 var repo = ObjectFactory.GetInstance<IRepository>();
   75                 var newUser = new AccountUser
   76                                   {
   77                                       Name = "Test",
   78                                       Email = "Email Test",
   79                                       Password = "Password Test"
   80                                   };
   81                 var newUser2 = new AccountUser
   82                                    {
   83                                        Name = "Test2",
   84                                        Email = "Email Test",
   85                                        Password = "Password Test"
   86                                    };
   87                 repo.Add(newUser);
   88                 repo.Add(newUser2);
   89 
   90                 uoW.Commit();
   91 
   92                 //Clear the session so its forced to go to the database and not pull from the cache
   93                 uoW.CurrentSession.Clear();
   94 
   95                 var returnedAccountUser = repo.GetById<AccountUser>(newUser.Id);
   96                 Assert.AreEqual("Test", returnedAccountUser.Name, "Failed to get user from database.");
   97             }
   98         }

so this test was to tell me that I could write more than 1 thing to the database at the same time on the same UnitOfWork. I did use the nhibernate profiler to spy on a little of what was going on here, which may I add is superb, easy to use, understand and set up. Going back to the test though, the UnitOfWork and StructureMap did their job nicely and only created one of them. One UnitOfWork was created as part of the 'using' and the one that was injected into the Repository creation (on line 74 of the test) was the same one. Superb! The data was added, the UnitOfWork commited and job done. I cleared the session at this point to force nhibernate to fetch the data from the database again rather than retrieve it from its cache.

Test to prove that there was a different UnitOfWork created when created in another thread.
  110        [TestMethod]
  111         public void Must_HaveNewSessionPerUoWPerThread()
  112         {
  113             ContainerBootstrapper.BootstrapStructureMap();
  114             //Create this instance on this thread.
  115             var uoW = ObjectFactory.GetInstance<IUnitOfWork>();
  116             IUnitOfWork uoW2;
  117 
  118             var thread = new Thread(x =>
  119             {
  120                 uoW2 = ObjectFactory.GetInstance<IUnitOfWork>();
  121                 Assert.AreNotSame(uoW, uoW2);
  122                 Assert.AreNotSame(uoW.CurrentSession, uoW2.CurrentSession);
  123             });
  124             thread.Start();
  125         }
with this test I am thinking along the lines I could use the UnitOfWork per HttpRequest using MVC some where along the lines, creating the UnitofWork in ActionExecting maybe and the commit/rollback on what ever the opposite one is. When I get to working that out I will post that next I think.

Changes I would like to make for an MVC web application.
I will get round to bloging what I did for this, but for short I am considering removing the UnitOfWork and Repository all together and let StructureMap create the Session and inject it into the controller constructors when they are created, but my only hesitation in this is that it will couple NHibernate to the controllers as they will need an ISession injected into them and also need to manage the Transaction.

5 comments:

  1. I don't know whether this is good design or bad, but a lot of people argue to put UOW inside repository

    ReplyDelete
    Replies
    1. Hey thanks for your comment, I am replying here as I am not sure if you would get a response if I just commented and not replied. See my comment :-) Will try to take a look at what you say and figure out again what I wrote :-)

      Delete
  2. Hello !!

    Thank's for the simplicity and the quality of you article. I really apreciate the reusable benefit on th DRY when you creating an abstract class to server as base respository class.

    While triying to do it myself, i got the idea to make all my Entity framework classe inherit from a Common class called Identifiable. This class only focus on the capability of classes to have an Id(mapped to the corresponding unique Id in database).

    Since i can identify every object with its Id, i can implement a concrete method GetById() like this :

    public T GetById(int id)
    {
    return this.Context.Set().Single(p => p.ID == id);

    }

    And finally i just have one an generic Class GenericRepository to manage my domain model.

    ReplyDelete
    Replies
    1. Hey there Mangesh, Thank for your comment, and your appreciation :-) I am replying here as I am not sure if you would get a response if I just commented and not replied. See my comment :-) Will try to take a look at what you say and see how it fits into what I have done, :-)

      Delete
  3. @Javafun, @Mangesh. Thank you very much for your comments. Sorry I haven't had time to look at your responses yet, I will take a look as soon as I can. I have been pretty inactive on here for a good while now, been busy working away. I will try and switch my brain back to the time I wrote these and take a look at what you guys say.

    ReplyDelete