Repository Pattern

Hacer Salman
3 min readMay 17, 2021

Merhaba,
Bugün sizlere yazılım dünyasında sıkça duyduğumuz bir design patternden bahsedeceğim, Repository Pattern. Bu pattern daha çok veritabanı erişimi yoğun olan projelerde tercih edilir yani veri merkezli projelerde. Bir projede birden fazla tablomuz olduğu zaman hepsi için ayrı ayrı insert, update, delete gibi işlemleri yapmak yerine bir kere bu işlemleri tüm tablolar için yapıp bizi hem kod kalabalığından hem de fazla iş yükünden kurtarır. Bu pattern kullanılarak veritabanı işlemlerini tek bir yerden yönetip diğer katmanlarda daha sade ve anlaşılır bir kod elde edilir.
Şimdi bu anlattıklarımı örnek bir proje üzerinde görelim. Projede .Net Core ve Entity Framework kullandım. Benim Cinema ve Movie diye iki sınıfım var bu sınıflar aynı zamanda veritabanı tabloları yani Entity sınıflarıdır.

public class BaseEntity
{
[Column(“id”)]
public long Id { get; set; }
}

public class Cinema:BaseEntity
{
[Column(“address”)]
[StringLength(1024)]
public string Address { get; set; }

[Column(“name”)]
[StringLength(512)]
[Required]
public string Name { get; set; }
}

public class Movie:BaseEntity
{
[Column(“description”)]
[StringLength(2048)]
public string Description { get; set; }

[Column(“type”, TypeName = “VARCHAR(64)”)]
public MovieType.Values Type { get; set; }

[Column(“rating”)]
public double Rating { get; set; }

[Column(“name”)]
[StringLength(512)]
[Required]
public string Name { get; set; }

[Column(“duration_type”, TypeName = “VARCHAR(32)”)]
public MovieDurationType.Values DurationType { get; set; }

[Column(“duration”)]
public int Duration { get; set; }
}

Bu sınıflara ait veritabanı işlemlerini yapmak için iki ayrı Repository sınıfına ihtiyacım var ancak bu iki sınıf için ortak yapılan create, update gibi işlemleri genel bir repository sınıfına almak işlerimizi daha da kolaylaştıracaktır. Bunun için ilk olarak ortak veritabanı işlemlerin gerçekleştirildiği sınıfımız için bir interface tanımlıyorum.

public interface IRepository<TEntity> where TEntity : class
{
ValueTask<TEntity> GetByIdAsync(long id);
Task<IEnumerable<TEntity>> GetAllAsync();
Task<bool> Update(TEntity entity);
Task<TEntity> AddAsync(TEntity entity);
List<TEntity> GetAll();
}

Şimdi bu arayüzü(interface) kullanarak veritabanı işlemlerini yapan sınıfımızı yazalım.

public class Repository<TEntity> : IRepository<TEntity> where TEntity : class
{
protected readonly MovieDbContext Context;

public Repository(MovieDbContext context)
{
this.Context = context;
}
public async Task<TEntity> AddAsync(TEntity entity)
{
await Context.Set<TEntity>().AddAsync(entity);
return entity;
}

public async Task<IEnumerable<TEntity>> GetAllAsync()
{
return await Context.Set<TEntity>().ToListAsync();
}

public List<TEntity> GetAll()
{
return Context.Set<TEntity>().ToList();
}

public ValueTask<TEntity> GetByIdAsync(long id)
{
return Context.Set<TEntity>().FindAsync(id);
}

public async Task<bool> Update(TEntity entity)
{
Context.Set<TEntity>().Update(entity);
return await Task.FromResult(true);
}
}

Şimdi ise sırada Cinema ve Movie için repository arayüz ve sınıflarımızı tanımlayalım.

public interface ICinemaRepository: IRepository<Cinema>
{
Task<Cinema> DeleteCinema(Cinema cinema);
Task<List<Cinema>> GetCinemasByName(string name);

}

public class CinemaRepository : Repository<Cinema>, ICinemaRepository
{
public CinemaRepository(MovieDbContext context)
: base(context)
{
}

public async Task<Cinema> DeleteCinema(Cinema cinema)
{
cinema.Status = EntityStatus.Values.DELETED;
return await Task.FromResult(cinema);
}

public async Task<List<Cinema>> GetCinemasByName(string name)
{
try
{
return await Context.Cinemas.AsNoTracking().Where(_ => _.Name.Contains(name) && _.Status == EntityStatus.Values.ACTIVE).ToListAsync();
}
catch (Exception)
{
throw;
}
}
}

public interface IMovieRepository: IRepository<Movie>
{
Task<Movie> DeleteMovie(Movie movie);
Task<List<Movie>> GetMoviesByName(string name);
}

public class MovieRepository : Repository<Movie>, IMovieRepository
{
public MovieRepository(MovieDbContext context)
: base(context)
{
}

public async Task<Movie> DeleteMovie(Movie movie)
{
movie.Status = EntityStatus.Values.DELETED;
return await Task.FromResult(movie);
}

public async Task<List<Movie>> GetMoviesByName(string name)
{
try
{
return await Context.Movies.AsNoTracking().Where(_ => _.Name.Contains(name) && _.Status == EntityStatus.Values.ACTIVE).ToListAsync();
}
catch (Exception)
{
throw;
}
}
}

Yukarıda bahsettiğim gibi bu sınıflar create,update ve veri listeleme işlemleri için ortak kullanılacak olan IRepository arayüzünden miras alıyorlar.
Yukarıda tanımladığım örnekte görüldüğü gibi veritabanı işlemleri sadece tek bir yerden yönetiliyor yani ben Cinema ile ilgili servis katmanında yapacağım işlemlerde veritabanına bağlantı açma ve veritabanı işlemleri yapmak yerine ICinemaRepository’i kullanmam yetecektir.

--

--