Repository Design Pattern

Çoğu yazılım uygulamasının belli mimari kurallar çerçevisinde farklı katmanlara ayrılarak geliştirilmesi beklenir ve buna n-tier architecture denir. N-tier architecture presentation tier, middle tier yada data tier gibi çeşitli katmanlardan oluşabilir. Presentation katmanında uygulamanızın UI tarafını ilgilendiren arayüzler bulunur, Middle katmanda business logic'i ilgilendiren geliştirmeler yapılır ve aynı zamanda database ile etkileşimde bu katmanda bulunur. Data katmanı ise uygulamanızdaki SQL Server, Oracle gibi database context'lerini içeren katmandır. Bu katman belkide uygulamadaki en önemli katmandır sebebi ise database. Data bizim için en önemli şey ve database'ler ile olan veri alış verişi işin en güvenlikli ve generic olması gereken yerlerin başında gelir.

Database varsa CRUD işlemi (Create, Read, Update, Delete) heralde olmazsa olmazdır ve data katmanı ile doğrudan business logic'in bulunduğu middle katman haberleşsin istenilmez ve bu durum bazen uygulamanızın büyüklüğüne göre çeşitli sorunlarda çıkartabilir. Repository pattern bu ihtiyacı karşılayan pattern olarak karşımıza çıkıyor ve temelde yaptığı iş ise business logic ile data access arasında arabulucu görevi görme.

Repository Pattern Faydaları

  • Maintainability (sonradan bakım kolaylılığı) arttırır,
  • Unit-test yapabilmemizi kolaylaştırır,
  • Esnek bir mimari uygulamamızı sağlar,
  • Yeni gelecek modüller veya istenilen değişiklikleri kolayca entegre edebilmeyi sağlar,
  • Domain driven development'ın önünü açar.

 

Repository Pattern Uygulaması

Şimdi örnek bir proje üzerinden Repository Pattern nasıl uygulanır görelim. Projeyi geliştirirken projenizde EntityFramework kurulu ve SampleDbContext adında bir database context'inizin olduğunu varsayarak ilerliyor olacağız.

1.Adım - IRepository adında CRUD işlemleri yapabilmemizi sağlayacak Generic bir interface metodlarını tanımlama.

public interface IRepository<T>  where T : class
    {
        IEnumerable<t> SelectAll();
        T SelectByID(object id);
        void Insert(T obj);
        void Update(T obj);
        void Delete(object id);
        void Save();
    }

2.Adım - BaseRepository adında Generic IRepository interface'inden implement olan class'ı oluşturma.

public abstract class BaseRepository<T> : IRepository<T> where T : class
    {
        private SampleDbContext db = null;
        private DbSet<t> table = null;
        public BaseRepository()
        {
            this.db = new SampleDbContext();
            table = db.Set<T>();
        }
        public BaseRepository(SampleDbContext db)
        {
            this.db = db;
            table = db.Set<T>();
        }
        public IEnumerable<T> SelectAll()
        {
            return table.ToList();
        }
        public T SelectByID(object id)
        {
            return table.Find(id);
        }
        public void Insert(T obj)
        {
            table.Add(obj);
        }
        public void Update(T obj)
        {
            table.Attach(obj);
            db.Entry(obj).State = EntityState.Modified;
        }
        public void Delete(object id)
        {
            T existing = table.Find(id);
            table.Remove(existing);
        }
        public void Save()
        {
            db.SaveChanges();
        }
    }

3.Adım - Employee adında örnek bir Entity tanımlama

public class Employee
{
    public int ID { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
}

 

4.Adım - BaseRepository den inherit olan Employee entity si için EmployeeRepository class'ını tanımlama

  public class EmployeeRepository : BaseRepository<Employee>
    {

    }

5.Adım - Yazmış olduğumuz EmployeeRepository'yi kullanmak

  void Main(string[] args)
        {
            var empRepository = new EmployeeRepository();
            empRepository.SelectAll();
        }

Projemiz hazır. Bundan sonra tanımlayacağınız entity'ler için EmployeeRepository de olduğu gibi Generic olarak yazmış olduğumuz BaseRepository'den türeyen Repository'ler tanımlayarak projeyi geliştirmeye devam edebiliriz.

Not : Bir rivayete göre Repository Design Pattern, Design Pattern ailesi içerisinde en çok kullanılan pattern olduğu söylenir.

 

Comments (5) -

  • Yazı için teşekkürler gayet sade ve anlaşılır dil ile anlatmışsınız.  
    • Merhaba, yorumlarınız için teşekkürler. Fırsat buldukça yazmaya devam edeceğim Smile
  • Hocam yazı için teşekkürler.
    Küçük bir sorum var.
    İçinde bulunduğum bir projede her entity class'ı için bir repository interface'i çağırılarak kullanılıyor. Anlamadığım olay neden her entity için interface oluşturduğumuz. Zaten her bir entity'e class üzerinden erişebiliyoruz. Ve her repo interface'i zaten 1 tane class implement ediyor aynı interface'i birden fazla entity implement etse mantığı oturacak ama her birinin kendi entity'si implement ediyor.  Direk interface yazmadan entity üzerinden işlemleri yapsak ne gibi problemler oluyor?
    • Selam Nevzat, tam olarak anlayamadım sorduğunu ? Örnek kod göndermen mümkün mü ?
      Eğer bahsettiğin şey; her bir entity'nin neden repository'si olduğu ise ?
      Repository pattern özünde db operasyonlarını tablo bazlı birbirinden ayırmak adına büyük öneme sahip. Hatta bir tablo ms-sql'de bulunuyorken diğer bir tabloyu postgre-sql'den kullanman gerekn durumlar olabilir veya bambaşka bir entity için dbContext yerine dapper gibi orm'ler kullanacağın bir durumda olabilir. Bu gibi durumlara karşı hep söylenen şey "separation of concerns" den yola çıkarak db de bulunan her bir tabloya karşı bir entity ve bu entity içinde bir repository katmanı gündelik hayatını oldukça kolaylaştıracaktır.

      Eğer sorduğun soru ; neden her bir entity için repository interface olduğu ise; neden dependency injection; her bir entity için ayrı ayrı interface'ler oluşturduğunda autofac, unity yada nhibernate gibi dependency injection tool'ları kullanarak bağımlılıkarı kolayca inject edebilirsin ve akabinde projende unit test yazarken kolaylık sağlayacaktır. Mock işlemi yaparken ilgili entity için kendi repository'sine ait kullanılan get,delete,getAll vs gibi metotlar için rahatca mocking işlemi yapmanı sağlayacaktır.
  • cem
    Teşekkürler.

Add comment