Question

I am working on ASP.NET MVC 4 project from scratch. I decided to start with the data access layer using Entity Framework 5 and Code First workflow. The company where I used to work was using very good implementation (in my opinion) of the Repository pattern including Repositories, Services, Abstract Factory for the Repositories and the Services and Unity for DI. I tried to redo it but it's just too complicated for me and will cost me a lot of time to replicate what I've been using there, so I decided to do some research and go with something lighter.

So I decided to use GenericRepository and UnitOfWork - far from what was the initial plan, but that was the implementation that was showing in most of my searches. So I did a very basic implementation (Just to the point where I'm sure I know what's going on, maybe even below my abilities to comprehend) and actually I think for this exact project it may be just enough but what I want is to be able to call additional custom methods on the different entities.

I think this gets a lot from the idea of generic repository, but if I try to go with some other implementation it's getting exponentially harder, so I wonder if there's a way to add this to my implementation without hurting too much the idea behind the generic Repository.

What I have now is the GenericRepository class :

public class GenericRepository<TEntity> where TEntity : class
    {
        internal DBContext context;
        internal DbSet<TEntity> dbSet;

        public GenericRepository(DBContext context)
        {
            this.context = context;
            this.dbSet = context.Set<TEntity>();
        }

        public virtual IEnumerable<TEntity> Get()
        {
            IQueryable<TEntity> query = dbSet;
            return query.ToList();
        }
        //just the standard implementation

and my UnitOfWork class :

public class UnitOfWork : IDisposable
    {
        private DBContext context = new DBContext();
        private CustomerRepository customerRepository;

        public CustomerRepository CustomerRepository
        {
            get
            {
                if (this.customerRepository == null)
                    this.customerRepository = new CustomerRepository(context);
                return customerRepository;
            }
        }

        private GenericRepository<Order> orderRepository;

        public GenericRepository<Order> orderRepository
        {
            get
            {

So as you may see my Order entity is using the GenericRepository but I made a test class CustomerRepository to use for my Customer entity.

For now this class CustomerRepository looks like this :

public class CustomerRepository : GenericRepository<Customer>
    {
        public CustomerRepository(DBContext context) : base(context) { }
    }

and the idea is to add the methods that are explicitly for the Customer entity here. I'm not sure if this is correct, especially the way I call the constructor. However, what is the natural way to add those specific methods for the different entities? I don't mind to even take a step back to implement it better but I don't want to rush it cause I tried and at the moment the whole concept is too complicated for me and I want to be sure that I understand the things that I use in my code.

Was it helpful?

Solution

I think you are on the right track. Here is the generic repository that I use:

public interface IRepository<TEntity>
    where TEntity : class
{
    IQueryable<TEntity> GetAll();
    IQueryable<TEntity> GetBy(Expression<Func<TEntity, bool>> predicate);
    TEntity GetById(long id);
    void Add(TEntity entity);
    void Update(TEntity entity);
    void Delete(TEntity entity);
}

public class Repository<TEntity> : IRepository<TEntity>
    where TEntity : class
{
    protected readonly DbEntities Context;
    protected readonly DbSet<TEntity> Set;

    public Repository()
    {
        Context = new DbEntities();
        Set = Context.Set<TEntity>();
    }

    public virtual IQueryable<TEntity> GetAll()
    {
        return Set;
    }

    public virtual IQueryable<TEntity> GetBy(Expression<Func<TEntity, bool>> predicate)
    {
        return Set.Where(predicate);
    }

    public virtual TEntity GetById(long id)
    {
        return Set.Find(id);
    }

    public virtual void Add(TEntity entity)
    {
        Set.Add(entity);
        Context.SaveChanges();
    }

    public virtual void Update(TEntity entity)
    {
        Set.Attach(entity);
        Context.Entry(entity).State = EntityState.Modified;
        Context.SaveChanges();
    }

    public virtual void Delete(TEntity entity)
    {
        Set.Remove(entity);
        Context.SaveChanges();
    }
}


// And assuming User is a data object with an Id property:
public interface IUserSpecificRepository
{
    List<User> GetById(long id)
}

public class UserSpecificRepository : IUserSpecificRepository, Repository<User>
{
    public virtual List<User> GetById(long id)
    {
        return GetBy(x => x.Id = id).ToList();
    }
}

Notice that GetAll() and GetBy() return a queryable. This is to allow control of when the query expression gets converted to SQL and hits the database. Usually a call to ToList() will cause this. You can then inherit from this and any custom methods can make use of these two starter methods.

Also, As a general rule of thumb, you should never do a GetAll().ToList() like you have now. If you have a zilion records you will run into problems. It is also a performance issue if you are filtering down to a few records. GetAll().ToList().Where(x => x.Id = 1) basically gets all zillion records from the db into memory, then filters it down to one. You should instead do this GetAll().Where(x => x.Id = 1).ToList().

Hope this helps you along!

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top