n3k
n3k

Reputation: 41

Repository Pattern + Unit Of Work

after almost a year I'm starting a new mvc project, this time with the version 4. I was wondering if the following implementation of repository pattern has more drawbacks than advantages.

public interface IRepository<T> where T : class
{
    IEnumerable<T> GetAll();

    IQueryable<T> Query(Expression<Func<T, bool>> filter);

    void Add(T entity);

    void Remove(T entity);
}

public interface IUnitOfWork
{
    void Commit();
}

public interface IDbContext : IDisposable
{
    IDbSet<T> Set<T>() where T : class;

    int SaveChanges();
}

public class DbContextAdapter : IDbContext
{
    private readonly DbContext _myRealContext;

    public DbContextAdapter()
    {
        this._myRealContext = new EstafaContext();
    }

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

    public IDbSet<T> Set<T>() where T : class
    {
        return _myRealContext.Set<T>();
    }

    public int SaveChanges()
    {
        return _myRealContext.SaveChanges();
    }
}

public class SqlRepository<T> : IRepository<T> where T : class
{
    private IDbSet<T> _dbSet;

    public SqlRepository(IDbContext dbContext)
    {
        this._dbSet = dbContext.Set<T>();
    }

    public IEnumerable<T> GetAll()
    {
        return this._dbSet.ToList();
    }

    public IQueryable<T> Query(Expression<Func<T, bool>> filter)
    {
        return this._dbSet.Where(filter);
    }

    public void Add(T entity)
    {
        this._dbSet.Add(entity);
    }

    public void Remove(T entity)
    {
        this._dbSet.Remove(entity);
    }
}

public class SqlUnitOfWork : IDisposable, IUnitOfWork
{
    private IDbContext _dbContext;

    private SqlRepository<Cliente> _clientes ;

    public SqlUnitOfWork()
    {
        this._dbContext = new DbContextAdapter();
    }

    public void Dispose()
    {
        if (this._dbContext != null)
        {
            this._dbContext.Dispose();
        }
        GC.SuppressFinalize(this);
    }

    public IRepository<Cliente> Clientes
    {
        get { return _clientes ?? (_clientes = new SqlRepository<Cliente>(_dbContext)); }
    }       

    public void Commit()
    {
        this._dbContext.SaveChanges();
    }
}

This way I can manage all repositories from a single point by means of SqlUnitOfWork. I used this design in a previous project and it worked pretty good but I feel it is not efficient and maybe redundant. Does it worth to add such a layer of abstraction?

Thanks in advance!

Upvotes: 4

Views: 833

Answers (2)

Didaxis
Didaxis

Reputation: 8746

I don't know if it has more drawbacks or advantages, but over the years, i've found this type of repository pattern to be less and less useful. Unless switching databases or data sources on the fly is a real possibility, or if you need some insane level of mock-the-universe test coverage, i think it's more hassle than it's worth.

Just my personal preference, but I like my data access methods to be a little more explicit. For instance, if i'm returning models to a view, they're definitely going to look different from the tables in my database. so i want a GetAllModelX method, NOT a GetAllDbTableRows method.

so where is this transformation code going to be housed? in the controller? another data access layer that converts entities to models? is there even a right or wrong answer? probably not.

i'm definitely playing devil's advocate a bit here, but in my experience, i've gotten away from this generic repository design in favor of a data access layer that returns/accepts models, and handles all the querying/CRUDding/UnitOfWork against the database using EF typically. But then again, I'm a classic unit-tester who doesn't do much mocking, and does more integration testing.

Upvotes: 1

armen.shimoon
armen.shimoon

Reputation: 6401

Although my implementations haven't been exactly as you have it, it seems pretty solid to me.

The only other change I typically do is define specific interfaces for each entity type repository, like this:

public interface IClienteRepository : IRepository<Cliente>
{
  IEnumerable<Cliente> GetByName(string firstName);
  // etc
}

That way I can still use all repositories generically for my CRUD operations, but I can also use the same repository to abstract away some querying logic. The user of your repository should only have to know what they want, not how to get it.

This, of course, is a bit more tedious, requiring you to make concrete implementations of your repositories that add extra functionality, but it just encapsulates query logic that you would have elsewhere through your application anyways.

Upvotes: 1

Related Questions