patterncsharpCritical
Unit of Work and Repository with Entity Framework 6
Viewed 0 times
withrepositoryworkentityandframeworkunit
Problem
Based on the reply of this question I have created the following code. I need to check whether it's good or not.
Here is my entity class:
This is my db context implementation:
Now I have implemented the
Here is the implementation:
The following is my controller code in ASP.NET MVC controller.
I want to check whether it is a good approach for TDD Test Driven Development or not.
Here is my entity class:
public class Employee
{
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string Designation { get; set; }
}This is my db context implementation:
public class MyDataContext : DbContext where T:class
{
private IDbSet _dbSet;
public MyDataContext() : base("name=DefaultConnectionString")
{
_dbSet = this.Set();
}
public MyDataContext(IDbSet dbSet )
: base("name=DefaultConnectionString")
{
this._dbSet = dbSet;
}
public IDbSet DbSetOjbect
{
get { return _dbSet; }
}
}Now I have implemented the
EmployeeService business logic class and the IEmployee service class:public interface IEmployeeService
{
List GetEmployees();
}Here is the implementation:
public class EmployeeService : IEmployeeService
{
private IDbSet employee;
public EmployeeService()
{
var employeeContext = new MyDataContext();
employee = employeeContext.DbSetOjbect;
}
public EmployeeService(IDbSet employee)
{
this.employee = employee;
}
public List GetEmployees()
{
return employee.ToList();
}
}The following is my controller code in ASP.NET MVC controller.
public class EmployeeController : Controller
{
private readonly IEmployeeService _employeeService;
public EmployeeController()
{
_employeeService = new EmployeeService();
}
public EmployeeController(IEmployeeService employeeService)
{
_employeeService = employeeService;
}
public ActionResult Index()
{
return View(_employeeService.GetEmployees());
}
}I want to check whether it is a good approach for TDD Test Driven Development or not.
Solution
I've never TDD'd, but don't do that:
This gives you a context-per-entity, which might work for ultra-simplistic CRUD scenarios, but doesn't scale very well and will quickly give you headaches as soon as you need to deal with more than a single entity type in a single transaction - because that's what a unit-of-work encapsulates: a transaction.
This blog entry sums it up pretty well. In a nutshell: embrace DbContext, don't fight it.
If you really want/need an abstraction, make your
Then you can easily implement it:
I don't like
I'd do it something like this, but I'm reluctant to use the entity types directly in the views, I'd probably have the service expose
public class MyDataContext : DbContext where T : classThis gives you a context-per-entity, which might work for ultra-simplistic CRUD scenarios, but doesn't scale very well and will quickly give you headaches as soon as you need to deal with more than a single entity type in a single transaction - because that's what a unit-of-work encapsulates: a transaction.
DbContext is a unit-of-work, and IDbSet is a repository; they are an abstraction; by wrapping it with your own, you're making an abstraction over an abstraction, and you gain nothing but complexity.This blog entry sums it up pretty well. In a nutshell: embrace DbContext, don't fight it.
If you really want/need an abstraction, make your
DbContext class implement some IUnitOfWork interface; expose a Commit or SaveChanges method and a way to get the entities:public interface IUnitOfWork
{
void Commit();
IDbSet Set() where T : class;
}Then you can easily implement it:
public class MyDataContext : DbContext, IUnitOfWork
{
public void Commit()
{
SaveChanges();
}
}I don't like
IEmployeeService either. This looks like an interface that can grow hair and tentacles and become quite a monster (GetByName, FindByEmailAddress, etc.) - and the last thing you want is an interface that needs to change all the time.I'd do it something like this, but I'm reluctant to use the entity types directly in the views, I'd probably have the service expose
EmployeeModel or IEmployee instead (see this question for more details - it's WPF, but I think lots of it applies to ASP.NET/MVC), so as to only have the service class aware of the Employee class, leaving the controller and the view working off some IEmployee implementation, probably some EmployeeModel class, idea being to separate the data model from the domain model.public class EmployeeService
{
private readonly IUnitOfWork _unitOfWork;
public EmployeeService(IUnitOfWork unitOfWork)
{
_unitOfWork = unitOfWork;
}
IEnumerable GetEmployees()
{
return _unitOfWork.Set().ToList();
}
}Code Snippets
public class MyDataContext<T> : DbContext where T : classpublic interface IUnitOfWork
{
void Commit();
IDbSet<T> Set<T>() where T : class;
}public class MyDataContext : DbContext, IUnitOfWork
{
public void Commit()
{
SaveChanges();
}
}public class EmployeeService
{
private readonly IUnitOfWork _unitOfWork;
public EmployeeService(IUnitOfWork unitOfWork)
{
_unitOfWork = unitOfWork;
}
IEnumerable<Employee> GetEmployees()
{
return _unitOfWork.Set<Employee>().ToList();
}
}Context
StackExchange Code Review Q#47879, answer score: 54
Revisions (0)
No revisions yet.