As there are many thoughts on design pattern compare to repository/UnitOfWork patten, here is the standard implementation of repository & business layer.
***DATA LAYER***
namespace app.data
{
public interface IGenericDataRepository<T> where T : class
{
IList<T> GetAll(params Expression<Func<T, object>>[] navigationProperties);
IList<T> GetList(Func<T, bool> where, params Expression<Func<T, object>>[] navigationProperties);
T GetSingle(Func<T, bool> where, params Expression<Func<T, object>>[] navigationProperties);
void Add(params T[] items);
void Update(params T[] items);
void Remove(params T[] items);
}
}
namespace app.data
{
public class GenericDataRepository<T> : IGenericDataRepository<T> where T : class
{
public virtual IList<T> GetAll(params Expression<Func<T, object>>[] navigationProperties)
{
List<T> list;
using (var context = new GatePassEntities())
{
IQueryable<T> dbQuery = context.Set<T>();
//Apply eager loading
foreach (Expression<Func<T, object>> navigationProperty in navigationProperties)
dbQuery = dbQuery.Include<T, object>(navigationProperty);
list = dbQuery
.AsNoTracking()
.ToList<T>();
}
return list;
}
public virtual IList<T> GetList(Func<T, bool> where,
params Expression<Func<T, object>>[] navigationProperties)
{
List<T> list;
using (var context = new GatePassEntities())
{
IQueryable<T> dbQuery = context.Set<T>();
//Apply eager loading
foreach (Expression<Func<T, object>> navigationProperty in navigationProperties)
dbQuery = dbQuery.Include<T, object>(navigationProperty);
list = dbQuery
.AsNoTracking()
.Where(where)
.ToList<T>();
}
return list;
}
public virtual T GetSingle(Func<T, bool> where,
params Expression<Func<T, object>>[] navigationProperties)
{
T item = null;
using (var context = new GatePassEntities())
{
IQueryable<T> dbQuery = context.Set<T>();
//Apply eager loading
foreach (Expression<Func<T, object>> navigationProperty in navigationProperties)
dbQuery = dbQuery.Include<T, object>(navigationProperty);
item = dbQuery
.AsNoTracking() //Don't track any changes for the selected item
.FirstOrDefault(where); //Apply where clause
}
return item;
}
public virtual void Add(params T[] items)
{
using (var context = new GatePassEntities())
{
foreach (T item in items)
{
context.Entry(item).State = EntityState.Added;
}
context.SaveChanges();
}
}
public virtual void Update(params T[] items)
{
using (var context = new GatePassEntities())
{
foreach (T item in items)
{
context.Entry(item).State = EntityState.Modified;
}
context.SaveChanges();
}
}
public virtual void Remove(params T[] items)
{
using (var context = new GatePassEntities())
{
foreach (T item in items)
{
context.Entry(item).State = EntityState.Deleted;
}
context.SaveChanges();
}
}
}
}
//Domain Models like Employee, Department can be your objectcontext, dbcontext (can be generated by EF or other ORM Tools like T4)
namespace app.data
{
public interface IEmployeeRepository : IGenericDataRepository<Employee>
{
}
public interface IDepartmentRepository : IGenericDataRepository<Department>
{
}
}
***BUSINESS LAYER***
namespace app.business
{
public interface IBusinessLayer
{
IList<Employee> GetAllEmployees();
IList<Employee> GetEmployeesByCountryName(string countryName);
Employee GetEmployeeByName(string EmployeeName);
Employee GetEmployeeByIdentityId(int identityId, string EmployeeUniqueIdentityNumber);
void AddEmployee(params Employee[] Employees);
void UpdateEmployee(params Employee[] Employees);
void RemoveEmployee(params Employee[] Employees);
}
}
public class BuinessLayer : IBusinessLayer
{
private readonly IEmployeeRepository _EmployeeRepository;
public BuinessLayer()
{
_EmployeeRepository = new EmployeeRepository();
}
public BuinessLayer(IEmployeeRepository EmployeeRepository)
{
_EmployeeRepository = EmployeeRepository;
}
public IList<Employee> GetAllEmployees()
{
return _EmployeeRepository.GetAll();
}
public IList<Employee> GetEmployeesByCountryName(string countryName)
{
return _EmployeeRepository.GetList(e => e.Country.Employees.Equals(countryName));
}
public Employee GetEmployeeByName(string EmployeeName)
{
return _EmployeeRepository.GetSingle(
d => d.Name.Equals(EmployeeName),
d => d.Country); //include related employees
}
public Employee GetEmployeeByIdentityId(int identityId, string EmployeeUniqueIdentityNumber)
{
var EmployeeIdentity = _EmployeeIdentityRepository
.GetSingle
(
q => q.IdentityId == identityId && q.UniqueIdentityNumber == EmployeeUniqueIdentityNumber);
Employee Employee = new Employee();
if (EmployeeIdentity != null)
{
Employee = _EmployeeRepository.GetSingle(o => o.EmployeeId == EmployeeIdentity.EmployeeId);
}
else
Employee = null;
return Employee;
}
public void AddEmployee(params Employee[] Employees)
{
try
{
_EmployeeRepository.Add(Employees);
}
catch (DbEntityValidationException dbEx)
{
foreach (var validationErrors in dbEx.EntityValidationErrors)
{
foreach (var validationError in validationErrors.ValidationErrors)
{
Trace.TraceInformation("Property: {0} Error: {1}", validationError.PropertyName, validationError.ErrorMessage);
}
}
}
}
public void UpdateEmployee(params Employee[] Employees)
{
/* Validation and error handling omitted */
_EmployeeRepository.Update(Employees);
}
public void RemoveEmployee(params Employee[] Employees)
{
/* Validation and error handling omitted */
_EmployeeRepository.Remove(Employees);
}
}
Now you can call business layer from the front-end