0
\$\begingroup\$

I know using a UnitOfWork/Repository pattern in a normal class should work fine without any issues but how about using them in a static class/methods (I mean using a private static IUnitOfWork instance, refer CustomerService class). Will this work fine in multiple user scenario without overlapping with other request (I am using asp.net)?

Can anyone please tell me whether the below code looks fine or I will get any issues (overlapping db issues) going forward because of the static IUnitOfWork instance? Also, please advice me if there is any other better way to do this.

public interface IDataRepository<T> where T : class
{
    IQueryable<T> Find(Expression<Func<T, bool>> predicate);
    IQueryable<T> GetAll();
    T GetById(Guid id);
    T GetById(int id);            
    void Add(T entity);
    void Update(T entity);
    void Remove(T entity);
}

public class DataRepository<T> : IDataRepository<T> where T : class
{

}

public interface IUnitOfWork
{
    IDataRepository<Customer> CustomerRepository { get; }
    IDataRepository<Product> ProductRepository { get; }

    void SaveChanges();
}

public class UnitOfWork : IUnitOfWork
{
    private readonly SomeContext _context;

    private IDataRepository<Customer> _customerRepository { get; set; }
    private IDataRepository<Product> _productRepository { get; set; }

    public UnitOfWork()
    {
        _context = new SomeContext();
    }        

    public IDataRepository<Customer> CustomerRepository
    {
        get
        {
            if (_customerRepository == null)
            {
                _customerRepository = new DataRepository<Customer>(_context);
            }
            return _customerRepository;
        }
    }

    public IDataRepository<Product> CustomerRepository
    {
        get
        {
            if (_productRepository  == null)
            {
                _productRepository = new DataRepository<Product>(_context);
            }
            return _productRepository;
        }
    }
}

public class CustomerService
{
    private static IUnitOfWork _unitOfWork = new UnitOfWork();

    public static List<Customer> GetCustomers()
    {
        _unitOfWork.CustomerRepository.Find(t => t.ID == 123).ToList();
    }

    public static bool IsCustomerExist()
    {
        return (_unitOfWork.CustomerRepository.Find(t => t.ID == 123).Count() > 0);
    }

    public static bool UpdateCustomer(Customer customer)
    {
        .....
        _unitOfWork.SaveChanges();
    }
}
\$\endgroup\$
1
\$\begingroup\$

It entirely depends on your implementation of the unit of works members. If the IDataRepository is using something like NHibernate and keeping open persistent connections (which, being part of a unit of work, I presume it might) you will absolutely run into weird database connectivity issues when using a private static member.

The reason for this, is that the static property is shared between all instances of the CustomerService, in your example, so you'll have one of those, and it'll be constructed with "whatever it gets at the time" - for example, the first database connection or session your application opens. If you have some sort of session per request handling that subsequently disposes of that session, the static class will still hold a reference to it, and you'll have a bad time.

To deal with this problem in some things that "must be" static, there's a cheap little trick you can use - add a static func to some form of resolver or container that you wire up at bootstrapping time:

public class ContainerRegistrationCode
{
    public void RegisterTypesInContainer()
    {
        Kernel.Bind<IUnitOfWork>().To<UnitOfWork>().InRequestScope();
        CustomerService.GetCurrentUnitOfWork = () => Kernel.GetService<IUnitOfWork>();
    }
}

public class CustomerService
{
    public static Func<IUnitOfWork> GetCurrentUnitOfWork { get; set; }

    public static List<Customer> GetCustomers()
    {
        var currentUnitOfWork = GetCurrentUnitOfWork ();
        currentUnitOfWork.CustomerRepository.Find(t => t.ID == 123).ToList();
    }
}

This way, you delegate out to a container or something that can manage the lifecycle of the unit of work, and every time you use it in a static context, you call the func which gets whatever the current one is.

It's a bit of a hack, don't use statics, use a good container instead that supports scoping (like Ninject) and you just shouldn't have this problem.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.