The Repository Design Pattern is used to abstract the data layer, making it easier to decouple the business logic and the data access logic. It acts as a mediator between the domain and the data mapping layers. The primary goal is to create a centralized data access logic that can be reused across the application.
Key Benefits
- Abstraction: Hides the details of data persistence.
- Testability: Easier to mock data repositories for unit testing.
- Maintainability: Encapsulates data access logic, making changes easier.
- Consistency: Provides a consistent interface for accessing data.
C# Example
Scenario
Let's create a simple example where we manage a list of products using the Repository Pattern.
Step 1: Define the Entity
public class Product
{
public int Id { get; set; }
public string Name { get; set; }
public decimal Price { get; set; }
}
Step 2: Define the Repository Interface
public interface IProductRepository
{
IEnumerable<Product> GetAllProducts();
Product GetProductById(int id);
void AddProduct(Product product);
void UpdateProduct(Product product);
void DeleteProduct(int id);
}
Step 3: Implement the Repository
using System.Collections.Generic;
using System.Linq;
public class ProductRepository : IProductRepository
{
private readonly List<Product> _products = new List<Product>();
public IEnumerable<Product> GetAllProducts()
{
return _products;
}
public Product GetProductById(int id)
{
return _products.FirstOrDefault(p => p.Id == id);
}
public void AddProduct(Product product)
{
_products.Add(product);
}
public void UpdateProduct(Product product)
{
var existingProduct = GetProductById(product.Id);
if (existingProduct != null)
{
existingProduct.Name = product.Name;
existingProduct.Price = product.Price;
}
}
public void DeleteProduct(int id)
{
var product = GetProductById(id);
if (product != null)
{
_products.Remove(product);
}
}
}
Step 4: Use the Repository in a Service
public class ProductService
{
private readonly IProductRepository _productRepository;
public ProductService(IProductRepository productRepository)
{
_productRepository = productRepository;
}
public void DisplayAllProducts()
{
var products = _productRepository.GetAllProducts();
foreach (var product in products)
{
Console.WriteLine($"ID: {product.Id}, Name: {product.Name}, Price: {product.Price}");
}
}
public void AddSampleProduct()
{
_productRepository.AddProduct(new Product { Id = 1, Name = "Laptop", Price = 75000 });
}
}
Step 5: Dependency Injection and Usage
class Program
{
static void Main(string[] args)
{
IProductRepository productRepository = new ProductRepository();
var productService = new ProductService(productRepository);
productService.AddSampleProduct();
productService.DisplayAllProducts();
}
}
Real-Time References
- E-commerce Systems: Repository pattern is used to manage products, customers, orders, and inventory data, abstracting the database interaction.
- Banking Applications: Managing accounts, transactions, and customers using repositories ensures modularity and easy testing.
- Healthcare Systems: Data access layers for patient records, appointments, and billing use repositories for efficient access and maintenance.
Best Practices
- Combine the Repository pattern with the Unit of Work pattern to handle transactions.
- Use dependency injection to inject repository instances.
- Avoid creating overly complex repository methods that duplicate logic better suited for services.
This approach ensures modular, testable, and maintainable code for any application.