pretzelb
pretzelb

Reputation: 1221

Generic repository pattern and multiple selects

I am trying to learn the repository pattern and looking at a generic repository I cannot see how to handle customized select statements. For example, using this article the author uses a select by ID and a select all.

public interface IGenericRepository<T> where T:class
{    
    IEnumerable<T> SelectAll();
    T SelectByID(object id);
    void Insert(T obj);    
    void Update(T obj);    
    void Delete(object id);    
    void Save();
}

Later the article the IGenericRepository interface is implemented using Northwind. Then that is used to create a Customer controller.

public class CustomerController : Controller
{    
    private IGenericRepository<Customer> repository = null; 
    public CustomerController()    
    {        
        this.repository = new GenericRepository<Customer>();    
    }
    ...

This would handle selecting a list of all Customers or for one Customer by ID but where I get stuck is some more real world examples like "select all Customers for a client" or "select all Customers for a region". Plus, you could have another controller based on a different entity that would filter on different attributes. I assume I'm missing something basic. If the user interface needed to present the Customer entity (or any other entity) by various filters, how would this be done by sticking with one generic repository?

Upvotes: 1

Views: 3817

Answers (3)

gmail user
gmail user

Reputation: 2783

An approach I've seen in one asp.net mvc based mission critical app, is to use the generic interface as defined in the question. Then there is an abstract class that implements that interface. And there is one more repository class that inherits the abstract class, which has all methods specific to that class.

public interface IGenericRepository<T> where T:class
{
 ...
}

public abstract class GenericRepository<T> : IGenericRepository where T:class
{
 ...
}

And the CustomerRepository class

public class CustomerRepository : GenericRepository<Customer>
{
 //add method specific to Customer like select Customers in specific country

}

And in the controller

public class CustomerController : Controller
{    
  private CustomerRepository  repository = null; 
  public CustomerController()    
  {        
    this.repository = new CustomerRepository();    
  }
  ...

Upvotes: 0

Yuliam Chandra
Yuliam Chandra

Reputation: 14640

I think the implementation of the GenericRepository should somehow be able to return the IQueryable of current entity, like adding Get() method.

protected IQueryable<T> Get() // Notice that the access modifier is protected.
{
   return table;
}

Then you could just create a derived class from GenericRepository and add a select method that accepts the Filter class.

public class CustomerRepository : GenericRepository<Customer>
{
   public IEnumerable<T> SelectAll(CustomerFilter filter){ .. }
}

The filter class contains 2 filters.

public class CustomerFilter
{
   public int? ClientId { get; set; }
   public int? RegionId { get; set; }
}

Then the SelectAll implementation would be.

public IEnumerable<T> SelectAll(CustomerFilter filter)
{
   var query = Get();
   if (filter == null)
   {
       return query;
   }

   if (filter.ClientId.HasValue)
   {
      query = query.Where(q => q.ClientId == filter.ClientId.Value);
   }

   if (filter.RegionId.HasValue)
   {
      query = query.Where(q => q.RegionId == filter.RegionId.Value);
   }

   return query;
}

In the controller, calling it like.

public ActionResult Get(int? clientId, int? regionId)
{
    var filter = new CustomerFilter { ClientId = clientId, RegionId = regionId };
    var customers = _repository.SelectAll(filter); 
    return View();
}

You might need to see this post as your reference.

Upvotes: 0

Ajay Kelkar
Ajay Kelkar

Reputation: 4621

Here you go; to handle any select criteria apart from the Id, you can add Where method like below

public interface IGenericRepository<T> where T:class
{    
    IEnumerable<T> SelectAll();
    T SelectByID(object id);
    IEnumerable<T> Where(Expression<Func<T,bool>> predicate)// this one 
    void Insert(T obj);    
    void Update(T obj);    
    void Delete(object id);    
    void Save();
}

Now in the Where method implementation do it like this

public IEnumerable<T> Where(Expression<Func<T,bool>> predicate)
    {
        return _objectSet.Where(predicate).AsEnumerable();
    }

Here _objectSet in created in repository constructor like this :

public Repository(ObjectContext context)
        {
            _context = context;
            _objectSet = _context.CreateObjectSet<T>();
         }

public CustomerController()
    {
        _context = new NorthwindEntities();
        _reporsitory = new Repository<Customer>(_context);

    } 

Use of Where method like

 reporsitory.Where(c=>c.Country=="Canada").ToList();

For full reference see this project on codeplex (download /browse source code) https://efgenericrepository.codeplex.com/SourceControl/latest

Upvotes: 6

Related Questions