Unit of Work ile Transaction Yönetimi

Birden fazla repository üzerinde eşzamanlı değişiklik yaparken, tutarlılığı sağlamak kritik önem taşır. Unit of Work (UoW) deseni, bir dizi veri erişim işlemini tek bir transaction altında toplar. Böylece:

  • Atomicity: Tüm işlemler ya hep başarılı olur ya da hiçbir değişiklik veritabanına yansımaz.
  • Tek Commit Noktası: SaveChanges() veya SaveChangesAsync() yalnızca bir kez çağrılır.
  • Temiz Kod: Servis katmanında transaction detayları yerine iş mantığına odaklanırsınız.

Tanım ve Prensipler

Unit of Work deseni, farklı repository’lerden gelen ekleme, güncelleme veya silme işlemlerini bir araya getirir ve bunları tek bir transaction içinde commit eder.
Başlıca sorumlulukları:

  1. Değişiklikleri takip etmek
  2. Tüm işlemleri tek seferde commit etmek
  3. Hata durumunda rollback sağlamak

Avantajlar & Dezavantajlar

Avantajlar

  • Transaction Tutarlılığı: Birden fazla repository çağrısı tek transaction’da toplanır.
  • Performans: Sadece bir SaveChanges() çağrısı, gereksiz tekrar commit’leri önler.
  • SRP Uyumu: Repository’ler sadece CRUD odaklı kalır; transaction yönetimi UoW’da toplanır.

Dezavantajlar

  • Ekstra Katman: Küçük projelerde basit CRUD işlemleri için gereksiz soyutlama olabilir.
  • Complexity: Transaction kapsamını geniş tutmak bazen performansı olumsuz etkileyebilir.

Pratik Not: Çok kısa ve basit bir ekleme/güncelleme işlemi için doğrudan repository üzerinden SaveChanges() çağırmak, küçük ve tek seferlik senaryolarda daha hızlı ve anlaşılır olabilir.

ASP.NET Core Örnek Uygulama

1. IUnitOfWork Arayüzü

public interface IUnitOfWork : IDisposable
{
    IRepository<Product> Products { get; }
    IRepository<Order> Orders { get; }
    Task<int> CommitAsync();
}

2. UnitOfWork Sınıfı

public class UnitOfWork : IUnitOfWork
{
    private readonly AppDbContext _context;

    public UnitOfWork(AppDbContext context)
    {
        _context = context;
        Products = new EfRepository<Product>(_context);
        Orders   = new EfRepository<Order>(_context);
    }

    public IRepository<Product> Products { get; }
    public IRepository<Order> Orders   { get; }

    public async Task<int> CommitAsync()
    {
        // Tüm değişiklikleri tek transaction içinde commit et
        return await _context.SaveChangesAsync();
    }

    public void Dispose()
    {
        _context.Dispose();
    }
}

3. Servis Katmanında Kullanımı

public class OrderService
{
    private readonly IUnitOfWork _unitOfWork;

    public OrderService(IUnitOfWork unitOfWork)
    {
        _unitOfWork = unitOfWork;
    }

    public async Task PlaceOrderAsync(Order order)
    {
        // Yeni siparişi ekle
        await _unitOfWork.Orders.AddAsync(order);

        // Stok güncelle
        var product = await _unitOfWork.Products.GetByIdAsync(order.ProductId);
        product.Stock -= order.Quantity;
        _unitOfWork.Products.Update(product);

        // İşlemleri commit et
        await _unitOfWork.CommitAsync();
    }
}

Not: CommitAsync() çağrısı yalnızca bir kez yapıldığı için, hem ekleme hem de güncelleme tek transaction’da gerçekleşir. Birinde hata olursa tüm işlem rollback olur.

Gerçek Projelerde Dikkat Edilmesi Gerekenler

  • Transaction Süresi: Uzun süren işlemler transaction’ı kilitleyebilir. Büyük batch işlemler için chunking stratejisi kullanın.
  • Concurrency Kontrolü: RowVersion veya optimistik kilitleme ile eş zamanlı güncellemelerde çakışmayı yönetin.
  • Logging: Hangi transaction’da hangi repository çağrılarının yapıldığını kaydedin; debug sürecini kolaylaştırır.
  • Hatayla Karşılaşma: CommitAsync() sırasında exception fırlarsa, işlem otomatik rollback olur; üst katmanda kullanıcıya anlamlı hata mesajı döndürün.

İleri Okuma ve Kaynaklar

Sonuç

Unit of Work deseni, özellikle çoklu repository çağrılarında veri tutarlılığını garanti altına alır.
Küçük, tek seferlik CRUD işlemlerinde ekstra katman getirmemek için pragmatik bir yaklaşım benimseyin. Projenizin ihtiyaçlarına göre UoW kullanımını dengeli tutarak kodunuzun hem temiz hem de güvenilir olmasını sağlayabilirsiniz.

By tanju.bozok

Software Architect, Developer, and Entrepreneur

Bir yanıt yazın

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