Projects are accessing data from various sources from
database, flat files to web services. The business layer of any particular
application consumes these accessed data in order to utilize in business logic.
The separation of concerns and the testability plays major role when we are
accessing data from various sources. The Repository design pattern provides us
generic solutions to these problems. Data access is not the only place where we
can use the repository pattern, but is the most used domain of this particular
design pattern.
Following diagram depicts a bird’s eye view of how the
repositories do the linkage between the data source and the business layer. The
Business logic would access in memory data from the repositories rather than
accessing the physical data source directly. And this clearly separates the
physical data access technologies and business logic technologies.
Following is an example of how to implement the employee
repository. Starting with the interface.
public interface IEmployeeRepo
{
void Add(Employee newEmp);
void Update(Employee emp);
void Remove(Employee emp);
IList<Employee> Search(Expression<Func<Employee, bool>> predicate);
Employee
GetById(int
empId);
}
Even though I have written the update method in this interface,
it is unlikely that in a real production system that we are having this kind of
individual update method. Mostly, we are using the UOW design pattern for the
atomic updates in the repositories.
The Search function is also using a LINQ predicate in order
to enable the calling entity to use LINQ queries for search features.
Following is an example of how to use this Interface when we
need to dealt with the Employee entity.
public class WorkingClass
{
public void DoWork(IEmployeeRepo repository)
{
repository.Add(new Employee());
repository.Search(x => x.Name == "James");
repository.GetById(23);
}
}
We need to create these repositories for each and every
entity in the application. Which is leading to a maintenance problem. Hence it
is advisable to create Generic repository to handle operations rather than
create repositories for each and every entity.
Following is a Sample
Interface for a generic repository.
public interface IRepository<T>
where T : class, IEntity
{
IQueryable<T> FindAll();
IQueryable<T> Search(Expression<Func<T, bool>> predicate);
T GetById(int id);
void Add(T newEntity);
void Remove(T entity);
}
We are using the generic type T to represent entities in
repository.
Following is the concrete implementation of the IRepository.
public class RepositoryImpl<T> : IRepository<T>
where T : class, IEntity {
public RepositoryImpl(ObjectContext context) {
_objectSet = context.CreateObjectSet<T>();
}
public IQueryable<T> Search (Expression<Func<T, bool>> predicate) {
return _objectSet.Where(predicate);
}
public void Add(T newEntity) {
_objectSet.AddObject(newEntity);
}
public void Remove(T entity) {
_objectSet.DeleteObject(entity);
}
public IQueryable<T> FindAll()
{
return _objectSet;
}
public T GetById(int id)
{
return _objectSet.Single(x => x.Id == id);
}
protected ObjectSet<T> _objectSet;
}
You can see that the object context playing a big role when
creating the repository instance. This is the actual entity framework context
we are using here to connect to the database. We can see that how it is converted the EF
specific operations on objects based on the required method.
One thing to note in GetById method, it requires the attribute
Id contains on each and every entity that we are dealing with. This is achieved
using the IEntiry interface which make sure all the inherited entities consist
of id attribute.
public interface IEntity {
int Id { get; }
}
Following depicts how we can use the IRepository implementation
in a worker class. As an example, I am using a web controller class.
public class WorkerController : Controller
{
public WorkerController()
:this(new SqlUnitOfWork())
{
}
public WorkerController(IUnitOfWork unitOfWork)
{
_unitOfWork = unitOfWork;
_repository = _unitOfWork.Employees;
}
public ViewResult Index()
{
var model = _repository.FindAll()
.OrderBy(e => e.dateRegistered);
return View(model);
}
public ViewResult Details(int id)
{
var model = _repository.FindById(id);
return View(model);
}
[HttpPost]
public ActionResult Edit(int id, FormCollection collection)
{
var model = _repository.FindById(id);
TryUpdateModel(model, new[] { "FirstName", "dateRegistered"
});
if (ModelState.IsValid)
{
_unitOfWork.Commit();
return RedirectToAction("Index");
}
return View(model);
}
private readonly IUnitOfWork _unitOfWork;
private readonly IRepository<Employee> _repository;
}
I have used the Unit Of Work pattern to perform transactions
against the db. You can find how the UOW is implemented in this post.
Ultimately , you can see that the controller class do not
need to bother about how this data been actually accessed by the respective repository.
This is the real power of this repository pattern.
No comments:
Post a Comment