Generic Repository & Unit Of Work
“Generic Repository” (Jenerik Depo) ve “Unit of Work” (İş Birimi) desenleri, özellikle veri erişim katmanını soyutlamak ve transaction…
Generic Repository & Unit Of Work
“Generic Repository” (Jenerik Depo) ve “Unit of Work” (İş Birimi) desenleri, özellikle veri erişim katmanını soyutlamak ve transaction yönetimini merkezi bir yerden sağlamak için kullanılan tasarım desenleridir. Bu iki desen birbirini tamamlar ve birlikte kullanıldığında daha sağlam, sürdürülebilir ve test edilebilir bir mimari sağlar.
Generic Repository (Jenerik Depo):
- Her veri modeli (örneğin
Product,User,Order) için tekrar tekrar CRUD işlemleri yazmamak adına jenerik hale getirilmiş birRepositoryyapısıdır. - Tipik metotlar:
Add,Update,Delete,GetById,GetAll,Find, vs
Unit of Work (İş Birimi):
- Transaction’ı merkezi şekilde yönetir.
- Tüm repository işlemlerinin bir araya getirilmesini sağlar.
- Genelde
SaveChanges()veyaCommit()metodu vardır. - Bu sayede birden fazla repository’den işlem yapılırsa, hepsi ya başarılı olur ya da başarısız (rollback) olur.
Bağlantı Noktaları:
1. UnitOfWork, birden fazla repository’i içinde barındırır.
- Yani tek bir
UnitOfWorknesnesi ileProductRepository,UserRepositorygibi tüm repository’lere ulaşabilirsin.
2. UnitOfWork, context’i paylaşır.
- Tüm repository’ler aynı
DbContext'i kullanır. Böylece işlemler bir bütün olarak değerlendirilir.
3. Tüm işlemlerden sonra UnitOfWork.Commit() çağrılarak veri tabanına değişiklikler yansıtılır.
- Bu da transaction mantığını sağlar.
Aşağıda Generic UnitOfWork ve Generic Repository için bir örnek yer alıyor.
UnitOfWork constructor da Generic olarak Entity almakta ve bunu Generic Repository oluşturmak için kullanmaktadır, ve yine UnitOfwork bünyesinde ki GetRepository metodu yardımı ile oluşturulan Repo’ nun Service tarafından kullanılması sağlanmaktadır.
//UnitOfWork
public interface IUnitOfWork : IDisposable
{
Task<int> CommitAsync();
}
public class UnitOfWork : IUnitOfWork
{
private readonly DbContext _context;
private readonly IRepository<T> _repository;
public UnitOfWork<T>(DbContext context) where T : BaseEntity
{
_context = context;
_repository = new Repository<T>(context);
}
public IRepository<T> GetRepository<T>() where T : BaseEntity
{
return _repository;
}
public async Task<int> CommitAsync()
{
return await _context.SaveChangesAsync();
}
public void Dispose()
{
_context.Dispose();
}
}
----------------------------------------------------------------------
//Repository
public interface IRepository<T> where T : BaseEntity
{
Task<T> GetByIdAsync(int id);
Task<IEnumerable<T>> GetAllAsync();
Task AddAsync(T entity);
void Update(T entity);
void Delete(T entity);
}
public class Repository<T> : IRepository<T> where T : BaseEntity
{
private readonly DbContext _context;
private readonly DbSet<T> _dbSet;
public Repository(DbContext 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);
}
public void Update(T entity)
{
_dbSet.Update(entity);
}
public void Delete(T entity)
{
_dbSet.Remove(entity);
}
}
------------------------------------------------------
//Service
public class UserService
{
private readonly IUnitOfWork<User> _unitOfWork;
private readonly IRepository<User> _repository;
public UserService(IUnitOfWork<User> unitOfWork)
{
_unitOfWork = unitOfWork;
_repository = _unitOfWork.GetRepository();
}
public async Task AddUserAsync(string name)
{
var user = new User { Name = name };
await _repository.AddAsync(user);
await _unitOfWork.CommitAsync();
}
public async Task<List<User>> GetUsersAsync()
{
return (await _repository.GetAllAsync()).ToList();
}
}
Bu örnekte; UnitOfWork katmanında Modeli Jenerik olarak alması sağlandığından Entity lere özel genişletilmiş Repo metodları yer almamaktadır. Fakat, unitOfWork te Entity Jenerik alınmayarak, Entity lere özel Repository ler oluşturulabileceği gibi Base Generic Repository kullanılmaya devam edilebilir.
Aşağıda bununla ilgili bir örnek yer almaktadır.
public interface IUnitOfWork : IDisposable
{
IRepository<Product> Products { get; }
IOrderRepository Orders { get; }
Task<int> CommitAsync(); // SaveChangesAsync
}
public class UnitOfWork : IUnitOfWork
{
private readonly AppDbContext _context;
public IRepository<Product> Products { get; }
public IOrderRepository Orders { get; }
public UnitOfWork(AppDbContext context)
{
_context = context;
Products = new Repository<Product>(_context);
Orders = new OrderRepository(_context);
}
public async Task<int> CommitAsync()
=> await _context.SaveChangesAsync();
public void Dispose()
=> _context.Dispose();
}
//REPOS
//////////////////////////////////////////////////////////////////////////////////
public interface IRepository<TEntity> where TEntity : class
{
Task<TEntity > GetByIdAsync(int id);
Task<IEnumerable<TEntity>> GetAllAsync();
Task<IEnumerable<TEntity>> FindAsync(Expression<Func<TEntity, bool>> predicate);
Task AddAsync(TEntity entity);
void Remove(TEntity entity);
void Update(TEntity entity);
Task<bool> AnyAsync(Expression<Func<TEntity, bool>> predicate);
Task<int> CountAsync();
}
//BASE GENERIC REPOSITORY
public class Repository<T> : IRepository<T> where T : class
{
protected readonly AppDbContext _context;
protected readonly DbSet<T> _dbSet;
public Repository(AppDbContext context)
{
_context = context;
_dbSet = context.Set<T>();
}
public virtual async Task<T> GetByIdAsync(int id)
=> await _dbSet.FindAsync(id);
public virtual async Task<IEnumerable<T>> GetAllAsync()
=> await _dbSet.ToListAsync();
public virtual async Task<IEnumerable<T>> FindAsync(Expression<Func<T, bool>> predicate)
=> await _dbSet.Where(predicate).ToListAsync();
public virtual async Task AddAsync(T entity)
=> await _dbSet.AddAsync(entity);
public virtual void Remove(T entity)
=> _dbSet.Remove(entity);
public virtual void Update(T entity)
=> _dbSet.Update(entity);
public virtual async Task<bool> AnyAsync(Expression<Func<T, bool>> predicate)
=> await _dbSet.AnyAsync(predicate);
public virtual async Task<int> CountAsync()
=> await _dbSet.CountAsync();
}
//ORDER REPOSITORY
public interface IOrderRepository : IRepository<Order>
{
Task<int> AddOrderAsync(Order order);
Task<int> AddProductAsync(Order order, Product product);
}
public class OrderRepository : Repository<Order>, IOrderRepository
{
public OrderRepository(AppDbContext context) : base(context)
{
}
public async Task<int> AddOrderAsync(Order order)
{
await _context.Orders.AddAsync(order);
//Sipariş ekleme ile ilgili özel işlemler.
//Örneğin Stokları güncelleme, bildirim gönderme vs.
await Task.Delay(100); // async simülasyonu
return 1;
}
//SİPARİŞE ÜRÜN EKLEME GİBİ ÖZEL BİR İŞLEM YAPILABİLİR.
public async Task<int> AddProductAsync(Order order, Product product)
{
await Task.Delay(100);
return 1;
}
}
//SERVICE
//////////////////////////////////////////////////////////////////////////////////
public class OrderService
{
private readonly IUnitOfWork _unitOfWork;
public OrderService(IUnitOfWork unitOfWork)
{
_unitOfWork = unitOfWork;
}
public async Task<bool> CreateOrderAsync(Order order)
{
await _unitOfWork.Orders.AddOrderAsync(order);
var result = await _unitOfWork.CommitAsync();
return result > 0;
}
} 메타데이터
- post_id
- c932ec82d6e2
- slug
- generic-repository-unit-of-work-c932ec82d6e2
- url
- https://medium.com/arvatotech/generic-repository-unit-of-work-c932ec82d6e2
- canonical_url
- https://medium.com/arvatotech/generic-repository-unit-of-work-c932ec82d6e2
- author_url
- https://medium.com/@doan.koc
- status
- ok
- fetched_at
- 2026-09-18 20:22:38