Repository Pattern কী?
Data access logic-কে business logic থেকে আলাদা করার pattern — DB code change করলে controller ভাঙবে না।
Generic Repository Interface
public interface IRepository<T> where T : class {
Task<T?> GetByIdAsync(int id);
Task<IEnumerable<T>> GetAllAsync();
Task<IEnumerable<T>> FindAsync(Expression<Func<T, bool>> predicate);
Task AddAsync(T entity);
void Update(T entity);
void Delete(T entity);
}
Implementation
public class Repository<T> : IRepository<T> where T : class {
protected readonly AppDbContext _ctx;
protected readonly DbSet<T> _set;
public Repository(AppDbContext ctx) {
_ctx = ctx;
_set = ctx.Set<T>();
}
public async Task<T?> GetByIdAsync(int id) => await _set.FindAsync(id);
public async Task<IEnumerable<T>> GetAllAsync() => await _set.ToListAsync();
public async Task<IEnumerable<T>> FindAsync(Expression<Func<T, bool>> p) => await _set.Where(p).ToListAsync();
public async Task AddAsync(T entity) => await _set.AddAsync(entity);
public void Update(T entity) => _set.Update(entity);
public void Delete(T entity) => _set.Remove(entity);
}
Unit of Work ⭐
একাধিক repository-কে একই transaction-এ commit/rollback করার pattern।
public interface IUnitOfWork : IDisposable {
IRepository<Product> Products { get; }
IRepository<Order> Orders { get; }
Task<int> SaveChangesAsync();
}
public class UnitOfWork : IUnitOfWork {
private readonly AppDbContext _ctx;
public IRepository<Product> Products { get; }
public IRepository<Order> Orders { get; }
public UnitOfWork(AppDbContext ctx) {
_ctx = ctx;
Products = new Repository<Product>(ctx);
Orders = new Repository<Order>(ctx);
}
public Task<int> SaveChangesAsync() => _ctx.SaveChangesAsync();
public void Dispose() => _ctx.Dispose();
}
// Program.cs
builder.Services.AddScoped<IUnitOfWork, UnitOfWork>();
Service Usage
public class OrderService {
private readonly IUnitOfWork _uow;
public OrderService(IUnitOfWork uow) => _uow = uow;
public async Task PlaceOrderAsync(Order order) {
await _uow.Orders.AddAsync(order);
var product = await _uow.Products.GetByIdAsync(order.ProductId);
product.Stock -= order.Qty;
_uow.Products.Update(product);
await _uow.SaveChangesAsync(); // single transaction
}
}
Pros & Cons
- ✅ Testable — mock IRepository
- ✅ Swap DB easily
- ❌ EF Core নিজেই DbContext = UoW + Repository pattern, তাই over-abstraction হতে পারে