Thought 1
public interface IRepository<T> : IDisposable where T : class
{
IQueryable<T> Fetch();
IEnumerable<T> GetAll();
IEnumerable<T> Find(Func<T, bool> predicate);
T Single(Func<T, bool> predicate);
T First(Func<T, bool> predicate);
void Add(T entity);
void Delete(T entity);
void SaveChanges();
}
with the above approach I will go like Repository and then have a Repository with the implementation of methods written above.
I think this frees my tests from DbContext dependency.
Thought 2
public class RepositoryBase<TContext> : IDisposable where TContext : DbContext, new()
{
private TContext _DataContext;
protected virtual TContext DataContext
{
get
{
if (_DataContext == null)
{
_DataContext = new TContext();
}
return _DataContext;
}
}
public virtual IQueryable<T> GetAll<T>() where T : class
{
using (DataContext)
{
return DataContext.Set<T>();
}
}
public virtual T FindSingleBy<T>(Expression<Func<T, bool>> predicate) where T : class
{
if (predicate != null)
{
using (DataContext)
{
return DataContext.Set<T>().Where(predicate).SingleOrDefault();
}
}
else
{
throw new ArgumentNullException("Predicate value must be passed to FindSingleBy<T>.");
}
}
public virtual IQueryable<T> FindAllBy<T>(Expression<Func<T, bool>> predicate) where T : class
{
if (predicate != null)
{
using (DataContext)
{
return DataContext.Set<T>().Where(predicate);
}
}
else
{
throw new ArgumentNullException("Predicate value must be passed to FindAllBy<T>.");
}
}
public virtual IQueryable<T> FindBy<T, TKey>(Expression<Func<T, bool>> predicate,Expression<Func<T, TKey>> orderBy) where T : class
{
if (predicate != null)
{
if (orderBy != null)
{
using (DataContext)
{
return FindAllBy<T>(predicate).OrderBy(orderBy).AsQueryable<T>(); ;
}
}
else
{
throw new ArgumentNullException("OrderBy value must be passed to FindBy<T,TKey>.");
}
}
else
{
throw new ArgumentNullException("Predicate value must be passed to FindBy<T,TKey>.");
}
}
public virtual int Save<T>(T Entity) where T : class
{
return DataContext.SaveChanges();
}
public virtual int Update<T>(T Entity) where T : class
{
return DataContext.SaveChanges();
}
public virtual int Delete<T>(T entity) where T : class
{
DataContext.Set<T>().Remove(entity);
return DataContext.SaveChanges();
}
public void Dispose()
{
if (DataContext != null) DataContext.Dispose();
}
}
I could now have CustomerRepository : RepositoryBase<Mycontext>,ICustomerRepository
ICustomerRepository
gives me the option of defining stuff like GetCustomerWithOrders
etc...
I am confused as to which approach to take. Would need help through a review on the implementation first then comments on which one will be the easier approach when it comes to Testing and extensibility.
Edit Revised after feedback.
public interface IRepositoryBase
{
int Delete<T>(T entity) where T : class;
void Dispose();
IQueryable<T> FindAllBy<T>(Expression<Func<T, bool>> predicate) where T : class;
T FindSingleBy<T>(Expression<Func<T, bool>> predicate) where T : class;
IQueryable<T> GetAll<T>() where T : class;
IQueryable<T> GetIncluding<T>(params Expression<Func<T, object>>[] includeProperties) where T:class;
int Save<T>(T Entity) where T : class;
int Update<T>(T Entity) where T : class;
}
public class RepositoryBase<TContext> : IDisposable, IRepositoryBase where TContext : DbContext,new()
{
private TContext _DataContext;
protected virtual TContext DataContext
{
get
{
if (_DataContext == null)
{
_DataContext = new TContext();
}
return _DataContext;
}
}
public virtual IQueryable<T> GetAll<T>() where T : class
{
using (DataContext)
{
return DataContext.Set<T>();
}
}
public virtual T FindSingleBy<T>(Expression<Func<T, bool>> predicate) where T : class
{
if (predicate != null)
{
using (DataContext)
{
return DataContext.Set<T>().Where(predicate).SingleOrDefault();
}
}
throw new ArgumentNullException("Predicate value must be passed to FindSingleBy<T>.");
}
public virtual IQueryable<T> FindAllBy<T>(Expression<Func<T, bool>> predicate) where T : class
{
if (predicate != null)
{
using (DataContext)
{
return DataContext.Set<T>().Where(predicate).AsQueryable<T>(); ;
}
}
throw new ArgumentNullException("Predicate value must be passed to FindBy<T,TKey>.");
}
public IQueryable<T> GetIncluding<T>(params Expression<Func<T, object>>[] includeProperties) where T: class
{
IQueryable<T> query = _DataContext.Set<T>();
foreach (var includeProperty in includeProperties)
{
query = query.Include(includeProperty);
}
return query;
}
public virtual int Save<T>(T Entity) where T : class
{
return DataContext.SaveChanges();
}
public virtual int Update<T>(T Entity) where T : class
{
return DataContext.SaveChanges();
}
public virtual int Delete<T>(T entity) where T : class
{
DataContext.Set<T>().Remove(entity);
return DataContext.SaveChanges();
}
public void Dispose()
{
if (DataContext != null) DataContext.Dispose();
}
}
Edit 2 :
I was writing tests against this using MOQ and NUnit. It fast turned into a nightmare of sorts. I went through the pain of my tests becoming dependent on EF. I do not think that is a good idea.Anyone have any ideas how to unit test RepositoryBase or as I see it I need to refactor and have a UnitOFWork. This has been a serious examination of my skills.
Edit 3 :
https://gist.github.com/4175430 I have put my new code there just the outline not the details inside . Now I am struggling with the ability to test this. I know the integration tests with a live db will give me the idea about Linq2Entities since testing this using Linq2Objects doesn't really make any sense.
With the answers mentioned below it seems like I need to have a service layer and my tests will have to be against this layer and not the repository since I should trust Microsoft with testing EF in the first place.