UnitOfWork implementation

Hello,

Ive been able to implement a little cool unit of work based on Serenarules one suggested in one thread.

I came up with …

public class UnitOfWork : IUnitOfWork
    {
        private Database _database;
        private IDatabaseFactory _databaseFactory;

        private DbTransaction transaction;

        public UnitOfWork(IDatabaseFactory databaseFactory)
        {
            _databaseFactory = databaseFactory;
            _database = Database;

            transaction = _database.Database.Connection.BeginTransaction();
        }

        public Database Database
        {
            get { return _database ?? (_database = _databaseFactory.Get()); }
        }

        public void Dispose()
        {
            try
            {
                _database.SaveChanges();
                transaction.Commit();
            }
            catch (Exception ex)
            {
                transaction.Rollback();
            }
        }
    }

I am pretty sure everyone is jealous of this unit of work now. (Kidding)

But i have a little design problem in this service layer.

public class JournalService : IJournalService
    {
        IJournalRepository _journalRepository;

        public JournalService(IJournalRepository journalRepository)
        { 
            _journalRepository = journalRepository;
        }

        public void AjouterJournal(Journal j)
        {
           [B]using (IUnitOfWork uow = new UnitOfWork())[/B]
            {
                var journal = new Journal();
                journalRepository.AddJournal(journal);

            }
        }
    }

The problem is the unit of work need a database injection so i cant create an instance of it. I can’t provide an unit of work directly in the service layer because it would make no sense since the unit of work need to be disposable.

And because i use repository to add my stuff there no need to access the unit of work directly, the saving will occur automaticly when it will be disposed anyway.

I could inject the IDatabaseFactory in my service layer but the idea is to not use it there. Actually the service layer shouldnt know about it.

How about an unit of work factory ?

Any ideas or suggestion?

public class UnitOfWorkFactory : Disposable, IUnitOfWorkFactory
    {
        private UnitOfWork _unitOfWork;
        private IDatabaseFactory _databaseFactory;

        public UnitOfWorkFactory(IDatabaseFactory databaseFactory)
        {
            _databaseFactory = databaseFactory;
        }

        public UnitOfWork Get()
        {
            return _unitOfWork ?? (_unitOfWork = new UnitOfWork(_databaseFactory));
        }

        protected override void DisposeCore()
        {
            if (_unitOfWork != null)
                _unitOfWork.Dispose();
        }
    }

This seem to be the solution. It is a clean solution ? It is okay to pass some parameters in a factory ?

Thanks.

First, the code, then the explanation. Direct from my personal foundation kit…

Enterprise.Foundation.Persistence.Providers.ISessionProvider.cs

using NHibernate;
namespace Enterprise.Foundation.Persistence.Providers
{
public interface ISessionProvider
{
ISession Current { get; set; }
}
}

Enterprise.Foundation.Persistence.Workers.IUnitOfWork.cs

using System;
using NHibernate;
namespace Enterprise.Foundation.Persistence.Workers
{
public interface IUnitOfWork : IDisposable
{
bool ThrowExceptions { get; set; }
ITransaction Transaction { get; }
}
}

Enterprise.Foundation.Persistence.Providers.IUnitOfWorkFactory.cs

using System.Data;
namespace Enterprise.Foundation.Persistence.Workers
{
public interface IUnitOfWorkFactory
{
IUnitOfWork Create(IsolationLevel isolationLevel = IsolationLevel.Unspecified);
}
}

Enterprise.Foundation.Persistence.Providers.UnitOfWork.cs

using System;
using NHibernate;
namespace Enterprise.Foundation.Persistence.Workers
{
public class UnitOfWork : IUnitOfWork
{
private ITransaction transaction;
public UnitOfWork(ITransaction transaction)
{
this.transaction = transaction;
}
public bool ThrowExceptions { get; set; }
public ITransaction Transaction
{
 
get { return transaction; }
 
}
public void Dispose()
{
if (transaction == null) return;
try
{
transaction.Commit();
}
catch (Exception exception)
{
if (ThrowExceptions) throw exception;
transaction.Rollback();
}
finally
{
transaction.Dispose();
}
 
}
}
}

Enterprise.Foundation.Persistence.Providers.UnitOfWorkFactory.cs

using System.Data;
namespace Enterprise.Foundation.Persistence.Workers
{
using Enterprise.Foundation.Persistence.Providers;
public class UnitOfWorkFactory : IUnitOfWorkFactory
{
private ISessionProvider sessionProvider;
public UnitOfWorkFactory(ISessionProvider sessionProvider)
{
this.sessionProvider = sessionProvider;
}
public IUnitOfWork Create(IsolationLevel isolationLevel = IsolationLevel.Unspecified)
{
return new UnitOfWork(sessionProvider.Current.BeginTransaction(isolationLevel));
}
 
}
}

Enterprise.Foundation.Web.Providers.SessionProvider.cs

using System.Web;
using NHibernate;
namespace Enterprise.Foundation.Web.Providers
{
using Enterprise.Foundation.Persistence.Providers;
public class SessionProvider : ISessionProvider
{
public ISession Current
{
get { return HttpContext.Current.Items["CurrentSession"] as ISession; }
set { HttpContext.Current.Items["CurrentSession"] = value; }
}
 
}
}

Now putting it all together is easy using dependency injection.

YourProject.Web.Global.asax (parts only)


protected void InitializeInjection()
{
// other code omitted
 
// register session provider implementation
container.Register(Component.For<ISessionProvider>().ImplementedBy<SessionProvider>());
 
// register unit of work factory implementation
container.Register(Component.For<IUnitOfWorkFactory>().ImplementedBy<UnitOfWorkFactory>());
 
// other code omitted
}
 
protected void Application_BeginRequest()
{
ISessionProvider sessionProvider = DependencyResolver.GetService<ISessionProvider>();
// initialize 'current' here
}
 
protected void Application_EndRequest()
{
ISessionProvider sessionProvider = DependencyResolver.GetService<ISessionProvider>();
// terminate 'current' here
}

Now, just make sure you inject IUnitOfWorkFactory into your controllers and services, along with your repositories. Then you can simply do:


using (var uow = unitOfWorkFactory.Create())
{
}
// or
using (var uow = unitOfWorkFactory.Create(IsolationLevel.ReadCommited))
{
}

The basic premise is centered around dependency injection. Let the system set things up for you as much as possible. Let the DI container inject ISessionProvider into your repositories and unitofworkfactory. Having done that, everything now shares the same session, and calls to repositories withing a using block, like above, and now wrapped in a transaction.

While my code is based around NHibernate, it could very easily be altered to support LinqToSql or EntityFramework.

Umm i think entity framework doesnt need the session thing. I am not using any session stuff and it seem to work that may be because i dont really understand how and why its used in your context. Also i am not using the same di container so your code seem obscur to me. Isnt the way im heading to any good at all? lol i feel lost a bit i have to deliver a project in 4 month and i want to start from a very good base while using my own implementations and avoid copying other code as much as possible. I need to fully understand what im coding and time isnt on my side right now.

Actually, you are using sessions. Your DbContext (you’re using CTP5 right) is a wrapper around it’s own session management. Just change ISessionProvider to IContextProvider and change the property of ‘Current’ to DbContext, instead of ISession. And you’ll need to change how UnitOfWorkFactory snags the transaction, and change ITransaction to DbTransaction. Other than that, the architecture remains the same. Feel free to play around with it.

I didn’t realise you were in a time-bind here…

That being the case, learning this now, may actually not be to your benefit if you don’t think you can do it within your time frame.

It’s really hard to say now, because I don’t know what the requirements of your solution are. Does it really require transactions? Are you doing batch updates and need the whole thing to fail if just one update fails?

That aside, your implementation is headed in the right direction. Three things to note though. 1) Dispose the transaction when done. 2) You are right about needing a db injection. In my case, I inject it into an IUnitOfWorkFactory and let the implementation pass it to each unit of work created. 3) Who says the service layer not need know about units of work? I have a CollationService in one app that takes both an IUnitOfWorkFactory and an IArticleRepository as constructor params. This is why we use interfaces and DI in the first place.

So after this all i have to do is inject the factory and the repositories in services and use it that way (with an using) ? Alright and what is doing the code in beginrequedt endrequest ?

Thanks.

It is storing a session (DbContext) in the request’s items collection. Making it a single session (db) per request.

You set it in App_BeginRequest…

IContextProvider cp = new ContextProvider();
cp.Current = new MyDomainContext();

and dispose of it in App_EndRequest…

IContextProvider cp = new ContextProvider();
DbContext current = cp.Current;
current.Close();
current.Dispose();

You use your DI to inject IContextProvider into your repositories and your unit of work factory. Then grab cp.Current and use it internally.

You use your DI to pass an IUnitOfWorkFactory and repositories into your controllers and services. Save the factory as a controller member just as you would the repositories, so you can call unitOfWorkFactory.Create().

BTW: Repositories shouldn’t be committing data on every operation. Don’t expose an Insert method, for example, that calls SaveChanges before returning. Just call Add on the context and expose SaveChanges as a separate method.

Since you are in a time crunch here, I took the liberty or recoding my own classes to use EF, and even provided a base repository class. Here’s the project source code. With these classes, all you have to do is initalize the current context in BeginRequest, dispose of it in EndRequest, and register IUnitOfWorkFactory to UnitOfWorkFactory and IContextProvider to ContextProvider in your DI container.

Oh man you probably saved me a lots of time its been about 2 weeks im struggle with this lol actually the only part that was left to he puzzle was the unit of work and how i would deal with the context dependency. I cant check the sources right away but will have a look tomorrow or monday. I dont know how many times i can thanks you not only you fixed the bug i had with mocks object lol but you had answers to many of my question here its the first time truly im seeing so much support from someone in a community. You really deserve your title member of the month. I am pretty sure many would Learn a lots from your blog posts that a good initiative. I still think that would not be fair to simply use your stuff but i can certaintly see that as a way to understand more underlying concepts and learn a lots from it even If my time are counted. So thanks you, will get back to you soon.

Btw… About your post explaining contextprovinder what i was intending to do is doing service injection in controller and repositories and unitofwork in service. What i was doing is a simple arhitecture using EF wih codefirst ctp5 whcih would support some concepts including transactions also for later use that why i wanted a good base. The idea was create the context from databasefactory then use it with an injection in unit of work and repositories which will be both injected in service layer.

The problem with using a database factory is that, unless you provide a way to cache it, and return the same instance each time, each call to databaseFactory.Create() will return a new instance and you will get cross-context errors. For example:


// simulating injection here...
IUserRepository ur = new UserRepository(databaseFactory.Create());
IPostRepository pr = new PostRepository(databaseFactory.Create());
 
Post existing = pr.SelectById(42);
existing.User = ur.SelectByUsername("Zaphod");
 
postRepository.Commit();

The above will throw errors, stating that you are trying to use an entity not associated with the current context.

If you change your database factory to cache a single instance of the context, then it’s pretty much the same as a context provider, and should work they way you want.

Be careful though, declaring it static is not safe. Store it in the HttpContext.Current.Items collection.

Yeah, i understand what your saying. I had this problem some day i realized that database factory was used in two class (unit of work and repository) called and accessed the problem is that my ninject was instancing a new instance for each. Instead ive added HttpScoped and it worked. I could use the same instance for each class which was working pretty well.

Here my database factory :

public class DatabaseFactory : Disposable, IDatabaseFactory
    {
        private Database _database;
        private string _connectionStringName;

        public DatabaseFactory(string connectionStringName)
        {
            // Need to be provided with a connection string name
            _connectionStringName = connectionStringName;
        }

        public Database Get()
        {
            return _database ?? (_database = new Database(_connectionStringName));
        }

        protected override void DisposeCore()
        {
            if (_database != null)
                _database.Dispose();
        }

    }

The idea was to build custom database context and switch them inbetween. Instead of passing a connection string i could pass a dictionnary of connection string and use them depending on database.

Ive looked at your sources and what i understand here is :

  • The ContextProvider offer a way to cache the DbContext so we can use the same everytime. You actually storing it in the httpcontext which encapsulates all HTTP-specific information about an individual HTTP request. So it is available only for the request. The context is actually provided in the startrequest and destroyed in the endrequest.
  • You do a commit from your repository instead of the unit of work. (In my project i do it from the unit of work but right now it is configured to do it once the transaction is disposed) is there a reason your using it in the repository ? The only reason i see is that you using the commit at the transaction level in the unit of work is only for doing transactions. There is a commit in the repository level which would enable you to use the repository without having to start a transaction. But what if you use 2 repository at the same time ? would you put the both repository access in a transaction then commit ?

What i am right on the two points above ?

The rest is very straighforward. From what i see its almost the same stuff as me except im implementing it differently. The implementation of the contextprovider is simpler and cleaner in your example, because you don’t have to deal with a database factory or storing the database context provided by the factory (which is what it is doing atm).

But as you stated about context errors i think there is no worry with my implementation so far it do exactly what you do. My DatabaseFactory create an instance but cache it (see post before this one) actually. DatabaseFactory is called in the unit of work and in the repository but both have the same instance injected in. (doing it through the di container) The repository is only there to manipulate data and the unit of work is here to commit the manipulated data.

Depending on which scope you use with ninject (I.E. IsRequestScope()), it’s the same thing. The object is instanced once, and is stored in HttpContext.Current.

Bingo. In my NHibernate base repository, I do not actually have a commit method. That’s only for the EF version, in case you have a simple one-shot insert or update, and don’t feel like you need a transaction. In my own apps, by convention, all non-queries are transactionalized, and my uow handles it.

At this point, I think you got it now. Good luck on your deadline. =)

Alright thanks a lots one more think related. Ive heard that actually its better with 2 levels of service layer. Someone spotted some insight saying you actually want to do more than just adding an entity to the repository in the service layer which is true but he also said that if you use only one level with an unit of work implementation you might end up reusing methods from the service that actually use the uow which is not really what you want because you will end up with usig two or more uow if you reuse methods in the service layer ( in other word if you need to call two methods in the servi e layer in one method in he service layer you will actually execute two transactions within one request. I just wanted your opinion on that what do you think ?

I’ll be honest, I’m not entirely sure I followed that. Are you asking about nested transactions where service.MethodA() using a unitofwork, service.MethodB() uses a service of work, and your controller action calls both, from within yet another UnitOfWork?

Indeed, that may cause problems. It depends on how your persistence engine handles transactions and how you code your unit of work.

With NHibernate, for instance, session.BeginTransaction() will, by default, either start one, or return the an existing one. That’s one transaction per session. Attempts at nesting them will invalidate the outermost one as soon as the deepest one disposes.

I’m not sure off hand how DbConnection handles them. It might be worth a look.

Yeah that what i meant. But as one suggested this can be fixed if you use a facade service (low level services) which call others services within it (high level ones) this is for avoiding the controller to have anything to do with that. But anyway there many ways to do it and all. I have everything i need to start the proiect so a big thanks to you ! If you have anything else to say regardig what ive said above feel free to add anything else.