Section 2 of 5
Repository Pattern
🎯 What You'll Learn
- What is Repository Pattern
- Creating repository interface
- Implementing repository
- Generic repository
- Using in controllers
What is Repository Pattern?
The Repository Pattern abstracts data access logic, providing a collection-like interface for accessing domain objects.
Benefits
- Separation of concerns: Business logic separate from data access
- Testability: Easy to mock repositories
- Maintainability: Centralized data access logic
- Flexibility: Easy to switch data sources
Repository Interface
IProductRepository.cs
C#
public interface IProductRepository
{
Task<Product> GetByIdAsync(int id);
Task<IEnumerable<Product>> GetAllAsync();
Task AddAsync(Product product);
Task UpdateAsync(Product product);
Task DeleteAsync(int id);
}
Repository Implementation
ProductRepository.cs
C#
public class ProductRepository : IProductRepository
{
private readonly InvenTrackDbContext _context;
public ProductRepository(InvenTrackDbContext context)
{
_context = context;
}
public async Task<Product> GetByIdAsync(int id)
{
return await _context.Products.FindAsync(id);
}
public async Task<IEnumerable<Product>> GetAllAsync()
{
return await _context.Products.ToListAsync();
}
public async Task AddAsync(Product product)
{
await _context.Products.AddAsync(product);
await _context.SaveChangesAsync();
}
public async Task UpdateAsync(Product product)
{
_context.Products.Update(product);
await _context.SaveChangesAsync();
}
public async Task DeleteAsync(int id)
{
var product = await _context.Products.FindAsync(id);
if (product != null)
{
_context.Products.Remove(product);
await _context.SaveChangesAsync();
}
}
}
Register Repository
Program.cs
C#
builder.Services.AddScoped<IProductRepository, ProductRepository>();
Generic Repository
IRepository.cs
C#
public interface IRepository<T> where T : class
{
Task<T> GetByIdAsync(int id);
Task<IEnumerable<T>> GetAllAsync();
Task AddAsync(T entity);
Task UpdateAsync(T entity);
Task DeleteAsync(int id);
}
Repository.cs
C#
public class Repository<T> : IRepository<T> where T : class
{
private readonly InvenTrackDbContext _context;
private readonly DbSet<T> _dbSet;
public Repository(InvenTrackDbContext context)
{
_context = context;
_dbSet = _context.Set<T>();
}
public async Task<T> GetByIdAsync(int id)
{
return await _dbSet.FindAsync(id);
}
public async Task<IEnumerable<T>> GetAllAsync()
{
return await _dbSet.ToListAsync();
}
public async Task AddAsync(T entity)
{
await _dbSet.AddAsync(entity);
await _context.SaveChangesAsync();
}
public async Task UpdateAsync(T entity)
{
_dbSet.Update(entity);
await _context.SaveChangesAsync();
}
public async Task DeleteAsync(int id)
{
var entity = await _dbSet.FindAsync(id);
if (entity != null)
{
_dbSet.Remove(entity);
await _context.SaveChangesAsync();
}
}
}
Using in Controller
ProductsController.cs
C#
public class ProductsController : Controller
{
private readonly IProductRepository _repository;
public ProductsController(IProductRepository repository)
{
_repository = repository;
}
[HttpGet]
public async Task<IActionResult> Index()
{
var products = await _repository.GetAllAsync();
return View(products);
}
[HttpPost]
public async Task<IActionResult> Create(Product product)
{
await _repository.AddAsync(product);
return RedirectToAction("Index");
}
}
Key Takeaways
- Repository Pattern: Abstracts data access
- Interface: Define contract for data operations
- Implementation: Encapsulate EF Core logic
- Generic Repository: Reusable for all entities
- Dependency Injection: Inject repository into controllers
- Benefits: Testability, maintainability, flexibility