I am creating a new project using business objects (Employee, Product). Due to constraints, I am not using LINQ to SQL or any ORM Mapper.
I have to hand code the Data Access Layer(s). I am interested in using the 'Repository Pattern'.
According to what I understand, I have to create a generic repository IRepository
which is implemented by all repositories ProductRepository, EmployeeRepository
.
What confuses me is that different business objects have different requirements. For example:
ProductRepository
GetAllProducts ();
GetProductById (int id);
GetProductByMaxPrice (double price);
GetProductByNamePrice (string name, double Price);
Get... (...);
EmployeeRepository
GetEmployeeByAge ();
GetEmployeeByJob (string description);
GetEmployeeBySalary (double salary);
Get... (...); //and so on
How can I create a generic repository which meets different data access requirements of different objects?
I have read a lot of theory regarding Repository Pattern but would really appreciate a working example.
Additionally, if I can create all repositories using a generic repository, using the factory pattern becomes easy aswell. For example:
interface IRepository
{
....
}
ProductRepository : IRepository
{
....
}
EmployeeRepository : IRepository
{
....
}
Then we can use the factory pattern effectively as:
IRepository repository;
repository = new ProductRepository ();
repository.Call_Product_Methods ();
repository = new EmployeeRepository ();
repository.Call_Employee_Methods ();
The Repository pattern has come in for a lot of criticism over the past few years by high-end . NET developers. This is understandable, because in most projects, the Repository layer is usually one of the worst-implemented parts of the codebase.
It is a data access pattern that prompts a more loosely coupled approach to data access. We create a generic repository, which queries the data source for the data, maps the data from the data source to a business entity, and persists changes in the business entity to the data source.
Entity Framework is a data access layer. Specifically it's an Object Relational Mapper.
A data access layer (DAL) in computer software is a layer of a computer program which provides simplified access to data stored in persistent storage of some kind, such as an entity-relational database. This acronym is prevalently used in Microsoft environments.
The repository Pattern is a great pattern to use, but if it is not done correctly, instead of making your life easier, it will be a huge pain!
So, the best possible way to do this (since you dont want to use EF or other ORM) is by creating a generic interface, and then a base abstract implementation. This way you dont need to code each repository, you can just instantiate them by the type!
And after this, if you have any particular method specific to some of your entities, you can all inherit from the Repository and override or add methods and properties as nedded.
If you want to use the Repository Pattern, i also suggest that you use the IUnitOfWork pattern, and keep it separated from the repository.
Both interfaces should look something like this:
The very simple IUnitOfWork:
Public interface IUnitOfWork
{
bool Save();
}
And them, the Repository interface, using generic:
public interface IRepository<TEntity> : IDisposable where TEntity : class
IUnitOfWork Session { get;}
IList<TEntity> GetAll();
IList<TEntity> GetAll(string[] include);
IList<TEntity> GetAll(Expression<Func<TEntity, bool>> predicate);
bool Add(TEntity entity);
bool Delete(TEntity entity);
bool Update(TEntity entity);
bool IsValid(TEntity entity);
}
The methods .Add(), .Delete() should not send anything to the database, but they should always send the changes to the IUnitOfWork (that you can implement in you DAL class), and only when you call the .Save() method of the IUnitOfWork you will save things to the Database.
I have implemented my Repository class using EntityFramework, and that makes things easier, but you can do it any way you want.
The code you will use will be somethin like this:
void SomeMethod()
{
using (IUnitOfWork session = new YourUnitOfWorkImplementation())
{
using (var rep = new Repository<Client>(session))
{
var client1 = new Client("Bob");
var client2 = new Cliente("John");
rep.Add(client1);
rep.Add(client2);
var clientToDelete = rep.GetAll(c=> c.Name == "Frank").FirstOrDefaut();
rep.Delete(clientToDelete);
//Now persist the changes to the database
session.Save();
{
{
}
Like i said, with EF and the DbContext, this is a lot easier, to here are a small part of my Repository class:
public class Repository : Component, IRepository
{
protected DbContext session;
{
get
{
if (session == null)
throw new InvalidOperationException("A session IUnitOfWork do repositório não está instanciada.");
return (session as IUnitOfWork);
}
}
public virtual DbContext Context
{
get
{
return session;
}
}
public Repository()
: base()
{
}
public Repository(DbContext instance)
: this(instance as IUnitOfWork)
{
#endregion
public IList<TEntity> GetAll<TEntity>() where TEntity : class
{
return session.Set<TEntity>().ToList();
}
public bool Add<TEntity>(TEntity entity) where TEntity : class
{
if (!IsValid(entity))
return false;
try
{
session.Set(typeof(TEntity)).Add(entity);
return session.Entry(entity).GetValidationResult().IsValid;
}
catch (Exception ex)
{
if (ex.InnerException != null)
throw new Exception(ex.InnerException.Message, ex);
throw new Exception(ex.Message, ex);
}
} ...
This way you dont need to build a GetEmployeeByAge, you would simply write:
IEnumerable<Employee> GetEmployee(int age)
{
return rep.GetAll<Employee>(e=> e.Age == age);
}
Or you could just call directly (no need to create the method)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With