Asp.net-mvc – Multiple generic repositories in unitofwork

asp.net-mvcentity-frameworkrepository-patternunit-of-work

Lets say I have 2 tables. ProductCategory and Product. I have 1 generic repository that can handle both tables:

public class GenericRepository<T> : IRepository<T>

But when using unit of work pattern, am I forced to create a repository for ALL tables in my database?

public interface IUnitOfWork : IDisposable
{
    int SaveChanges();

    IRepository<ProductCategory> ProductCategoryRepository { get; }
    IRepository<Product> ProductRepository { get; }
}

Is there not a way I can add the generic repository to the unit of work class?

Best Solution

You can add a generic method to the IUnitOfWork interface:

public interface IUnitOfWork : IDisposable
{
    int SaveChanges();

    IRepository<T> Repository<T>();
}

But i don't recommend it. It's smells like Service Locator anti-pattern and SRP violation. Better way is to remove all repositories from the IUnitOfWork interface, because providing access to repository is not UnitOfWork's responsibility. I recommend to separate repository from UnitOfWork and inject their into the consumer by itself.

public class Consumer
{
    private readonly IUnitOfWork _unitOfWork;
    private readonly IRepository<Product> _products;

    public Consumer(IUnitOfWork unitOfWork, IRepository<Product> products)
    {
        _unitOfWork = unitOfWork;
        _products = products;
    }

    public void Action()
    {
        var product = _products.GetOne();

        product.Name = "new name";
        _products.Update(product);

        _unitOfWork.SaveChanges();
    }
}

UDATE:

UnitOfWork and Repository can share context instance. Here the sample of code:

public class EfUnitOfWork : IUnitOfWork
{
    private readonly DbContext _context;

    public EfUnitOfWork(DbContext context)
    {
        _context = context;
    }

    public void SaveChanges()
    {
        _context.SaveChanges();
    }
}

public class EfRepository<T> : IRepository<T> where T : class
{
    private readonly DbContext _context;

    public EfRepository(DbContext context)
    {
        _context = context;
    }

    //... repository methods...
}

public class Program
{
    public static void Main()
    {
        //poor man's dependency injection
        var connectionString = "northwind";

        var context = new DbContext(connectionString);
        var unitOfWork = new EfUnitOfWork(context);
        var repository = new EfRepository<Product>(context);
        var consumer = new Consumer(unitOfWork, repository);
        consumer.Action();
    }
}
Related Question