I have read a number of posts regarding the implementation of a generic repository. I have also read a number of posts that explain the difference between exposing IEnumerable vs. IQueryable from my repository.
I would like the flexibility of having my data filtered in the database (rather than in memory by the client) but want to avoid having to define a separate repository interface for all of my entities (and concrete classes that implement those interfaces).
So far my repository looks like this:
public interface IRepository<T>
{
IEnumerable<T> GetAll();
IEnumerable<T> Find(Expression<Func<T, bool>> where);
void Add(T entity);
void Attach(T entity);
void Delete(T entity);
}
and an example of a concrete implementation is:
public class Repository<T> : IRepository<T> where T : class
{
private DbContext _context;
private DbSet<T> _entitySet;
public Repository(DbContext context)
{
_context = context;
_entitySet = _context.Set<T>();
}
public IEnumerable<T> GetAll()
{
return _entitySet;
}
public IEnumerable<T> Find(Expression<Func<T, bool>> where)
{
return _entitySet.Where(where);
}
public void Add(T entity)
{
_entitySet.Add(entity);
}
public void Attach(T entity)
{
_entitySet.Attach(entity);
}
public void Delete(T entity)
{
_entitySet.Remove(entity);
}
}
In this case my repository uses DbContext so what I would like to know is how this works with the generic interface:
IQueryable<T>derives fromIEnumerable<T>. In My find method I am returning anIQueryable<T>object but the client only sees this as anIEnumerable<T>. Does this mean that if I carry out any subsequent queries on theIEnumerable<T>object it will actually perform the operations on the database and only return the results (because the object is aIQueryablein this case)? Or,- Only the
Whereclause that is passed into theFindmethod is executed on the database and any subsequent queries that are performed on theIEnumerable<T>object are performed on the client. Or, - Neither of these happen and I have totally misunderstood how
IEnumarable<T>,IQueryable<T>andLinqworks.
Update:
I am actually fairly surprised at the answers I have received in the comments. My original repository returned IQueryable and subsequent research led me to believe this was a bad thing to do (e.g. if my viewModel accepts a repository in its constructor it can call any query it wants which makes it is more difficult to test).
All solutions I have seen for this so far involve create entity specific repositories so that IQueryable is not exposed (The only difference I guess is that I am doing this in a generic way).