Generic Repository Nedir ve Neden Kullanılır?

Generic Repository, farklı entity’ler için ortak CRUD işlemlerini tek bir sınıfta soyutlamanızı sağlar. Bu sayede:

  • Kod Tekrarı Azalır: Her entity için ayrı repository yazmak yerine tek bir generic sınıf kullanırsınız.
  • Bakım Kolaylığı: Yeni entity eklediğinizde repository tarafında ekstra kod yazmanıza gerek kalmaz.
  • Tutarlılık: Tüm CRUD operasyonları aynı implamentasyondan beslenir, davranış farkları minimize edilir.

Tasarım Prensipleri

  1. Single Responsibility (SRP): Generic repository sadece veri erişim metotlarını barındırır.
  2. Open/Closed (OCP): Yeni entity türü eklemek için repository sınıfı değiştirilmez, sadece T tipi değişir.
  3. Dependency Inversion (DIP): Servis katmanı, concrete sınıfa değil IRepository<T> arayüzüne bağımlı olur.

Pratik Not: Eğer bazı entity’leriniz çok özel sorgulara ihtiyaç duyuyorsa, generic repository’yi base olarak kullanıp o entity’ye özgü metotlar içeren “specialized” repository’ler türetebilirsiniz.

ASP.NET Core ile Örnek Uygulama

1. IRepository<T> Arayüzü

public interface IRepository<T> where T : class
{
    Task<T> GetByIdAsync(int id);
    Task<IEnumerable<T>> GetAllAsync();
    IQueryable<T> Query();
    Task AddAsync(T entity);
    void Update(T entity);
    void Delete(T entity);
}
  • Query() metodu, LINQ filtreleri servis katmanına bırakmak için IQueryable<T> döner.

2. EfRepository<T> Sınıfı

public class EfRepository<T> : IRepository<T> where T : class
{
    protected readonly AppDbContext _context;
    public EfRepository(AppDbContext context) => _context = context;

    public async Task<T> GetByIdAsync(int id) =>
        await _context.Set<T>().FindAsync(id);

    public async Task<IEnumerable<T>> GetAllAsync() =>
        await _context.Set<T>().ToListAsync();

    public IQueryable<T> Query() =>
        _context.Set<T>().AsNoTracking();

    public async Task AddAsync(T entity) =>
        await _context.Set<T>().AddAsync(entity);

    public void Update(T entity) =>
        _context.Set<T>().Update(entity);

    public void Delete(T entity) =>
        _context.Set<T>().Remove(entity);
}

Örnek Kullanım:

var products = await _repository.Query()
                                .Where(p => p.IsActive)
                                .OrderBy(p => p.Name)
                                .ToListAsync();

Gerçek Projelerde Dikkat Edilmesi Gerekenler

  • AsNoTracking: Sadece okunacak verilerde AsNoTracking() kullanarak performansı artırın.
  • Sorgu Filtreleme: Özel filtreler veya eager loading gereken durumlarda Query() üzerinden LINQ kullanın.
  • Transaction Yönetimi: Birden fazla entity güncellemesi varsa UnitOfWork ile beraber kullanın; tek bir commit’te tüm değişiklikleri uygulayın.
  • Specialized Repository: Generic yapının yeterli olmadığı karmaşık sorgular için IProductRepository : IRepository<Product> gibi arayüzler oluşturup, sadece o sorgulara özgü metotlar ekleyin.

Servis Katmanına Entegrasyon

public class ProductService
{
    private readonly IRepository<Product> _repository;
    private readonly IUnitOfWork _unitOfWork;

    public ProductService(IRepository<Product> repository, IUnitOfWork unitOfWork)
    {
        _repository  = repository;
        _unitOfWork = unitOfWork;
    }

    public async Task<IEnumerable<Product>> GetActiveProductsAsync()
    {
        return await _repository.Query()
                                .Where(p => p.IsActive)
                                .ToListAsync();
    }

    public async Task AddProductAsync(Product product)
    {
        await _repository.AddAsync(product);
        await _unitOfWork.CommitAsync();
    }
}

İleri Okuma ve Kaynaklar

Sonuç

Generic Repository, projedeki temel CRUD işlemlerini tek bir yerde toplamak için güçlü bir yöntemdir. Ancak:

  • Çok farklı sorgulara ihtiyaç duyulan entity’lerde specialized repository’ler kullanarak esnekliği koruyun.
  • Query() metoduyla LINQ izinleri verin, ancak AsNoTracking() ve eager loading detaylarına dikkat edin.

Doğru dengede kullandığınızda, kod tekrarını azaltır, bakımı kolaylaştırır ve test edilebilirliği artırırsınız.

By tanju.bozok

Software Architect, Developer, and Entrepreneur

Bir yanıt yazın

E-posta adresiniz yayınlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir