I'm new to this Repository pattern and have seen lot of repository pattern + UoW implementations all over the internet and I'm not able to reach to a conclusion as to which of them is correct . After going through many links I've been able to implement one .
Considering the following points in mind
- It should satisfy SOLID principles
- Be testable
- Be independent of framework
- Be independent of DB
Here is the code of the implementation
Generic IRepository
public interface IRepository<T> where T : class
{
void Add(T entity);
void Update(T entity);
void Delete(T entity);
T GetByKey(object id);
}
RepositoryBase
public abstract class RepositoryBase<D, T> : IRepository<T> where T : class where D : BaseDbContext
{
private D dataContext;
private readonly IDbSet<T> dbSet;
protected IDbFactory<D> DbFactory
{
get;
private set;
}
protected D DbContext
{
get { return dataContext ?? (dataContext = DbFactory.Init()); }
}
protected RepositoryBase(IDbFactory<D> dbFactory)
{
DbFactory = dbFactory;
dbSet = DbContext.Set<T>();
}
#region Implementation
public virtual void Add(T entity)
{
dbSet.Add(entity);
}
public virtual void Update(T entity)
{
dbSet.Attach(entity);
DbContext.Entry(entity).State = EntityState.Modified;
}
public virtual void Delete(T entity)
{
dbSet.Remove(entity);
}
public T GetByKey(object id)
{
return dbSet.Find(id);
}
#endregion
}
IUnitofWork , UnitOfWork
public interface IUnitOfWork<D> where D : BaseDbContext
{
void Commit();
}
public class UnitOfWork<D> : IUnitOfWork<D> where D : BaseDbContext, new()
{
private readonly IDbFactory<D> dbFactory;
private D dbContext;
public UnitOfWork(IDbFactory<D> dbFactory)
{
this.dbFactory = dbFactory;
}
public D DbContext
{
get { return dbContext ?? (dbContext = dbFactory.Init()); }
}
public void Commit()
{
DbContext.SaveChanges();
}
}
IDBFactory ,DBFactory
public interface IDbFactory<D> where D : BaseDbContext
{
D Init();
}
public class DbFactory<D> : Disposable, IDbFactory<D> where D : BaseDbContext, new()
{
D dbContext;
public D Init()
{
return dbContext ?? (dbContext = new D());
}
protected override void DisposeCore()
{
if (dbContext != null)
dbContext.Dispose();
}
}
BaseDbContext
public abstract class BaseDbContext : DbContext
{
public BaseDbContext(string nameOrConnectionString) : base(nameOrConnectionString)
{
}
}
ProjectDbContext
public partial class ProjectDbContext : BaseDbContext
{
public ProjectDbContext()
: base("name=ProjectDbContext")
{
Database.SetInitializer<ProjectDbContext>(null);
}
}
EXAMPLE USAGE
Controller
public class StudentsController : BaseController
{
private IStudentBusiness objstudentbusiness;
public StudentsController(IStudentBusiness rstudentbusiness)
{
objstudentbusiness = rstudentbusiness;
}
public JsonResult LoadStudents()
{
var data = objstudentbusiness.ListStudents();
var jsonResult = Json(data, JsonRequestBehavior.AllowGet);
return jsonResult;
}
}
IStudentBAL,StudentBAL
public interface IStudentBAL
{
void SaveStudent(StudentDto student);
List<StudentDto> ListStudents();
}
public class StudentBAL : BusinessBase, IStudentBAL
{
private readonly IStudentRepository objStudentRepository;
private readonly IUnitOfWork<ProjectDbContext> objIUnitOfWork;
public StudentBAL(IStudentRepository rIStudentRepository, IUnitOfWork<ProjectDbContext> rIUnitOfWork)
{
try
{
objStudentRepository = rIStudentRepository;
objIUnitOfWork = rIUnitOfWork;
}
catch (Exception ex)
{
Log.Error(ex);
}
}
public List<StudentDto> ListStudents()
{
try
{
var tusrs = objStudentRepository.ListStudents() ?? new List<StudentDto>();
return tusrs;
}
catch (Exception ex)
{
Log.Error(ex);
}
return new List<StudentDto>();
}
}
IStudentRepository,StudentRepository
public interface IStudentRepository
{
void SaveStudent(Student Student);
StudentDto GetStudentByName(StudentDto Studentname);
Student GetStudentByID(int Studentid);
List<StudentDto> ListStudents();
}
public class StudentRepository : RepositoryBase<ProjectDbContext, Student>, IStudentRepository
{
public StudentRepository(IDbFactory<ProjectDbContext> dbFactory) : base(dbFactory)
{
}
public List<StudentDto> ListStudents()
{
var students = (from t in DbContext.Students
select new StudentDto
{
// all the required properties
}).ToList();
return students;
}
}
- Dependency Injection is done using AutoFac
- Code for logging is omitted
I am asking if this seems like a good implementation or am I missing anything?
I would appreciate any feedback on my implementation you can offer regarding correctness, efficiency, and any suggestions. So here are my questions
- Is this loosely coupled ?
- Is it having any leaky abstraction and why ?
- What needs to be done to switch from EF to another ORM such as Dapper or to simple ADO.net and how much effort would it require to implement the changes?
- Is this pattern breaking any of the SOLID princples ,Law or Demeter or any Object Oriented laws?
- Does this pattern have any code redundancies which are not required ?
- How this architecture using EF would scale with a project containing more than 100+ domain entities and with each entity having at least more than 10 fields . Is it going to be maintenance nightmare later on?
-All criticisms greatly appreciated !!
EDIT : What needs to be done to switch from EF to another ORM such as Dapper or to simple ADO.net and how much effort would it require to implement the changes?
private readonly IDbSet<T> dbSet;
. Also see blog.ploeh.dk/2012/03/26/IQueryableTisTightCoupling \$\endgroup\$