Repository Design Pattern
Repository Design Pattern separates the data access layer from the business layer by adding an additional layer of abstraction between them.
In repository pattern, business logic can access the data object without having knowledge of the underlying data access layer.
Possible use cases for repository pattern
1. Underlying data source or data access layer need to change.
2. Hiding the complexity of data access layer.
3. Centralized handling of the domain objects.
Implementation
Implementation of the repository pattern include following steps
1. Create an Interface IProductRepository.
2. Add abstract methods for CRUD operation like Add(), Update(), Delete() and Get() in above interface as shown below.
- //Interface for product repository
- public interface IProductRepository
- {
- Product Get(int Id);
- void Add(Product entity);
- void Update(Product entity);
- void Delete(int Id);
- }
3. Create ProductRepository class which implements IProductRepository as shown below.
- //Implementation
- public class ProductRepository :IProductRepository
- {
- protected readonly DbContext db;
- public ProductRepository(DbContext _db)
- {
- db = _db;
- }
- public Product Get(int Id)
- {
- return db.Products.Find(Id);
- }
- public void Add(Product entity)
- {
- db.Products.Add(Product);
- }
- public void Delete(object Id)
- {
- Product entity = db.Products.Find(Id);
- this.Remove(entity);
- }
- public void Update(Product entity)
- {
- db.Entry(entity).State = EntityState.Modified;
- }
- }
4. You can now interact with data access layer by creating the instsnce of ProductRepository class as shown below.
- IProductRepository productRepo = new ProductRepository();
- //add product
- productRepo.Add(productObject);
- //update product
- productRepo.Update(productObject)
Unit of Work in the Repository Pattern
Unit of work refer the way of executing in-memory database CRUD operations on dependent entities as one transaction. If any operation fails then entire db operations will be rollback.
Consider the following example to understand the concept
Lets say we have two dependent repositories Product and Order, both will maintain their own instance of the DbContext and will have its own in-memory list of changes that are added,updated and deleted. In such a case, if SaveChanges of one of the repository fails and other one succeeds, it will bring inconsistency in database.
To solve this problem, add a layer on the top of these repositories that will help to share common the instance of the DbContext. This will ensure all the changes among the dependent repositories should act as a unit of transaction that will either complete or fail entirely with database rollback.
1. Create an interface that contains Product and Order as dependent repositories object as shown below
- //Interface for unit of work repository
- public interface IUnitOfWork : IDisposable
- {
- IOrderRepository Order { get; }
- IProductRepository Products { get; }
- int SaveChanges();
- }
2. Create a UnitOfWork class that implements the interface IUnitOfWork as shown below
- public class UnitOfWork : IUnitOfWork
- {
- private readonly DbContext db;
- public UnitOfWork()
- {
- db = new DbContext();
- }
- private IOrderRepository _Order;
- public IOrderRepository Order
- {
- get
- {
- if (this._Order == null)
- {
- this._Order = new OrderRepository(db);
- }
- return this._Order;
- }
- }
- private IProductRepository _Products;
- public IProductRepository Products
- {
- get
- {
- if (this._Products == null)
- {
- this._Products = new ProductRepository(db);
- }
- return this._Products;
- }
- }
- public int SaveChanges()
- {
- return db.SaveChanges();
- }
- }
3. Now create a instance of new layer IUnitOfWork and do the changes on their respective repositories as shown below.
- IUnitOfWork unitOfWork = new UnitOfWork();
- //add product details
- unitOfWork.Products.Add(productObject);
- //add order details
- productRepo.Order.Add(orderObject);
- unitOfWork.SaveChanges();
4. Finally call the SaveChanges method that shares a common instance of DbContext to ensure inconsistent changes should not go into the database.
Advantages of Repository pattern
1. De-couples the business logic and the data access layers that helps to change underlying data sources or architecture without affecting the business logic.
2. Code becomes easy to maintain and helps in fast integration of additional feature like data caching or analytics.
Comments
Post a Comment