17
\$\begingroup\$

I am new to learning Repository Pattern. I am developing a site in MVC 4 (I'm new to it as well).

The way I am using Repository pattern as follows:

  1. I created IRepository<T> interface as follows:

    public interface IRepository<T>    
    {        
        void Insert(T entity);
        void Delete(T entity);
        IQueryable<T> SearchFor(Expression<Func<T, bool>> predicate);
        IQueryable<T> GetAll();
        T GetById(int id);
    }
    
  2. Then I created a base class which implements the above interface as follows:

    public class BaseRepository<TEntity> : IRepository<TEntity> where TEntity : class
    {
        private readonly DbContext _dbContext;
    
        public BaseRepository(DbContext dbContext)
        {
            _dbContext = dbContext;
        }
    
        public void Insert(TEntity entity)
        {
            _dbContext.Set<TEntity>().Add(entity);
            _dbContext.SaveChanges();
        }
    
        public void Delete(TEntity entity)
        {
            _dbContext.Set<TEntity>().Remove(entity);
            _dbContext.SaveChanges();
        }
    
        public IQueryable<TEntity> SearchFor(Expression<Func<TEntity, bool>> predicate)
        {
            return _dbContext.Set<TEntity>().Where(predicate);
        }
    
        public IQueryable<TEntity> GetAll()
        {
            return _dbContext.Set<TEntity>();
        }
    
        public TEntity GetById(int id)
        {
            return _dbContext.Set<TEntity>().Find(id);
        }
    }
    
  3. Now for each repository I want to create, I create another interface which contains methods specific to that class. E.g if I want to create a CustomersRepository, I create an interface ICustomersRepository as follows:

    public interface ICustomersRepository: IRepository<Customer>
    {
        IEnumerable<Customer> GetRecentCustomers();
        Customer GetByName(string customerName);
    }
    
  4. Now I create CustomersRepository class, derive it from BaseRepository and implement ICustomersRepository. as follows:

    public class CustomersRepository : BaseRepository<Customer>, ICustomersRepository
    {
        private readonly DbContext _dbContext;
    
        public CustomersRepository(DbContext dbContext) : base(dbContext)
        {
            _dbContext = dbContext;
        }
    
        public IEnumerable<Customer> GetRecentCustomers()
        {
            // implementation
        }
    
    
        public Customer GetByName(string customerName)
        {
            //
        }
    }
    

Now to create another Repository, I will have to create an interface for it, then create that repository class which will implement BaseRepository<TEntity> class, implement the specific repository interface.

Issues:

  1. This is not the proper way. But I use it as I get a BaseRepository<TEntity> which gives me many functions implemented.
  2. I have to pass DbContext for each repository class.
  3. not satisfied

Can you please guide me have this code corrected? I will be using the same approach in almost all of my future projects where I use an ORM.

\$\endgroup\$
  • \$\begingroup\$ Implementation seem fine to me but if you like you could drop the IRepository<T> and have only abstract BaseRepository<T>. \$\endgroup\$ – Mikko Viitala Feb 22 '15 at 19:49
14
\$\begingroup\$
  1. You can make DbContext protected property in your base implementation, so you don't have to declare it in every single derived class.

  2. You might want to consider extracting Insert and Delete methods to separate interface, because often you want to make some of your repositories readonly.

    Implementation may look like that:

    interface IRepository<T>    
    {        
        IQueryable<T> SearchFor(Expression<Func<T, bool>> predicate);
        IQueryable<T> GetAll();
        T GetById(int id);
    }
    
    interface IEditableRepository<T> : IRepository<T>
    {
        void Insert(T entity);
        void Delete(T entity);
    }
    
    class ReadOnlyRepositoryBase<T> : IRepository<T>
    {...}
    
    class EditableRepositoryBase<T> : ReadOnlyRepositoryBase<T>, IEditableRepository<T>
    {...}
    

    this way you can distinct readonly repositories from non-readonly at compilation time.

  3. Passing dbContext to every repository is not normally an issue, because usually in addition to your repositories, you also implement factory object, which creates your repositories for you, so you don't have to call constructor explicitly. This factory can be made a singleton, so you can access it at any point in your code. Alternatively, you can register your repositories in some container, or you can use both approaches. If you are familiar with inversion of control and dependency injection (because there is definitely a learning curve), your best bet is to use a container.

    Here is an example (using Castle Windsor):

    public class RepositoryFactory : IDisposable
    {
        private IWindsorContainer _container;
    
        public void Open()
        {
            _container = new WindsorContainer();
    
            //register dependencies
            _container.Register(Component.For<DbContext>().ImplementedBy<DbContext>());
    
            //register repositories
            _container.Register(Component.For<ICustomersRepository>().ImplementedBy<CustomersRepository>());
        }
    
        public TRepository GetRepository<TRepository>() where TRepository : class
        {
            return _container.Resolve<TRepository>();
        }
    
        public Dispose()
        {
            if (_container == null) return;
            _container.Dispose();
            _container = null;
        }
    
        public void Close()
        {
            Dispose();
        }
    }
    

    Then you can use it like this:

    var f = new RepositoryFactory();
    f.Open();
    var rep = f.GetRepository<ICustomersRepository>();
    f.Close();
    

    Alternatively, you can implement your own container using reflection to instantiate your repositories, or you can use a dictionary. Or w/e, really. This implementation is obviously no singleton, but nothing stops you making one, if you feel like it.

Apart from that, your implementation looks fine to me. I didn't quite get your first issue though.

\$\endgroup\$
  • \$\begingroup\$ Thanks a lot for the answer. The first issue is that I cannot use only interface in any controller's constructor. like "public myController(ICustomersRepository repository". because the "ICustomersRepository" has only a few methods. Is'nt this bad? \$\endgroup\$ – Aamir Jun 21 '13 at 10:54
  • \$\begingroup\$ @Aamir why only a few? ICustomersRepository extends IRepository<Customer> so it should give you access to both: methods declared in base interface (GetAll(), etc..) and methods declared in derived interface (GetByName(), etc). Or am missing your point? \$\endgroup\$ – Nikita B Jun 21 '13 at 11:30
  • \$\begingroup\$ thanks a lot ... it was indeed my mistake... i m ashamed for that silly question. OK .. I will implement your first advice. I am not sure about your second advice.. i mean y would i need to create a separate interface? ... and can u please give me an example of your third advice? \$\endgroup\$ – Aamir Jun 21 '13 at 18:30
  • \$\begingroup\$ #2 is a great idea. \$\endgroup\$ – Sully Apr 22 '16 at 13:21

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.