egoodberry
egoodberry

Reputation: 2766

Passing Data Context from Unit of Work Into Repositories

I've been using repositories for data access for some time now but have never successfully implemented anything resembling the Unit of Work pattern. I've started a new project for self-education using RavenDB and ASP.NET MVC (details that should be trivial, in theory) and am looking to establish a good way to wrap business transactions (not web requests) in their own units of work, but am having some difficulty doing so.

The following code snippet is what I'd like to see:

public class UserService : IUserService
    {
        private readonly IRepository<User> _userRepository;
        private readonly IRepository<Role> _roleRepository;

        public UserService(
               IRepository<User> userRepository, 
               IRepository<Role> roleRepository)
        {
            _userRepository = userRepository;
            _roleRepository = roleRepository;
        }

        public void Register(User user)
        {
            using (var session = UnitOfWork.Begin())
            {
                _userRepository.Create(user);
                _roleRepository.AddToRole(user, Role.Public);
                session.Commit();
            }
        }
    }

My first stab at a unit of work interface looks something like this:

 public interface IUnitOfWork : IDisposable
    {
        void Commit();
    }

    public class UnitOfWork : IUnitOfWork
    {
        private readonly IDocumentSession _session;

        public UnitOfWork(IDocumentStore documentStore)
        {
            _session = documentStore.OpenSession("http://from:config");
        }

        public void Commit()
        {
            _session.SaveChanges();
        }

        public static IUnitOfWork Begin()
        {
            return IoC.GetInstance<IUnitOfWork>();
        }

        public void Dispose()
        {
            _session.Dispose();
        }
  }

Where I'm stuck is the repositories' access to the database session. As I mentioned, I'd like to wrap business transactions in their own units; I'm also not keen on passing the session / context into each method, and most other solutions I've seen use static methods and / or storage in something like the web session. All of these make me a little uncomfortable; is there something key that I'm missing to this whole Unit of Work concept?

Upvotes: 3

Views: 2175

Answers (2)

egoodberry
egoodberry

Reputation: 2766

I'm not fond of the TransactionScope concept, and further research & discussion has led me to believe that what I am trying to do is simply not feasible.

In the end, the repositories within the UnitOfWork's context need to (explicitly) know about the UnitOfWork. I haven't settled on which way to go just yet, but I'm going to do something like one of the following:

using (var session = UnitOfWork.Begin())
            {
                _userRepository.Use(session).Create(user);
                _roleRepository.Use(session).AddToRole(user, Role.Public);
                session.Commit();
            }

or

using (var session = UnitOfWork.Begin())
            {
                session.Get<IUserRepository>().Create(user);
                session.Get<IRoleRepository>().AddToRole(user, Role.Public);
                session.Commit();
            }

I'm not crazy about either approach; I'll mark this as the answer until I receive a better suggestion.

Upvotes: 1

user793390
user793390

Reputation: 46

Julia Lerman has some great examples of the Unit of Work using Entity Framework.

In entity framework it is supported in the context so it is very easy to implement a unit of work. The main problem I would see is how do you manage the order. Example: Table A and Table B

Table B has a foreign key to Table A. Your unit of work would have to know to order otherwise it would error out. I would just go with an OR/M like Nhibernate or EF. It should make like a lot easier.

Upvotes: 0

Related Questions