- 7 Şub 2012
- 5,018
- 22
Selamlar, bu yazımda sizlere Repository Design pattern ve Entity Framework ile kullanımını anlatacağım.
Konunun amacı entity frameworkün kendisini anlatmak değil, repository pattenr i entity framework ile birlikte kullanabilmek. O yüzden detaylı entity framework bilgisi arıyorsanız yanlış konudasınız. Temel entity framework bilginiz olduğunu varsayıyorum.
Nedir bu repository pattern?
Yazılım geliştirirken, tasarım aşamasında birçok tasarım desenleri kullanılır. Creational, behavioral, structural temel başlıkları altında patternler mevcuttur. Bunları araştırmanızın size çok büyük katkıları olacaktır. Özellikle GOF design patterns.
Repository nin Martin Fowler ın sözleriyle anlamına bir bakalım :
"Repository: Mediates between the domain and data mapping layers using a collection-like interface for accessing domain objects."
Domain objelerine erişim için kullanılan bir arayüz olarak bahsedebiliriz kendisinden.
Database işlemlerinde yaptığımız temel işlemleri CRUD olarak özetleyebiliriz. Yani Create, Read, Update, Delete.
Bu işlemleri tek bir interface üzerinde tanımlayıp, bunları domain objelerine özel implement eden concrete nesnelerimiz olursa, bunun adı repository olmuş olur.
Sözel kısmı geçip kod tarafında implementasyonuna bakalım.
Entity sınıflarımız ve DbContext sınıfımız:
Kod:
public class User
{
public int Id { get; set; }
public string Name { get; set; }
public string Password { get; set; }
public string Role { get; set; }
}
public class Product
{
public int Id { get; set; }
public string ProductName { get; set; }
}
public class MyDbContext : DbContext
{
public TurDbContext(DbContextOptions options) : base(options)
{
}
protected override **** OnModelCreating(ModelBuilder modelBuilder)
{
}
public DbSet<User> Users { get; set; }
public DbSet<Product> Products { get; set; }
}
IRepository interface imiz :
Kod:
public interface IRepository<T> where T : class
{
T Create(T t);
T Get(int id);
IEnumerable<T> List();
IQueryable Query(Expression<Func<T,bool>> query);
IQueryable Query();
**** Update(T t);
**** Delete(T t);
}
Concrete UserRepository sınıfımız :
Kod:
public class UserRepository : IRepository<User>
{
private readonly TurDbContext _context;
private readonly DbSet<User> _dbSet;
public UserRepository(TurDbContext context)
{
_context = context;
_dbSet = context.Set<User>();
}
public User Create(User t)
{
_dbSet.Add(t);
_context.SaveChanges();
return t;
}
public User Get(int id)
{
return _dbSet.Find(id);
}
public IEnumerable<User> List()
{
return _dbSet.ToList();
}
public IQueryable<User> Query(Expression<Func<User, bool>> query)
{
return _dbSet.Where(query);
}
public IQueryable<User> Query()
{
return _dbSet.AsQueryable();
}
public **** Update(User t)
{
_dbSet.Update(t);
_context.SaveChanges();
}
public **** Delete(User t)
{
_dbSet.Remove(t);
_context.SaveChanges();
}
}
Elimizde bulunan bu classlarımızla artık uygulamamız içerisinden User ile ilgili database işlemlerini yapabiliriz.
Repository nin uygulamamızda kullanımını göstermek için örnek bir servis katmanı kodunu veriyorum :
Kod:
public class UserService
{
private readonly UserRepository _repository;
public UserService(UserRepository repository)
{
this._repository = repository;
}
public IEnumerable<User> GetUsers()
{
var Users = _repository.List();
return Users;
}
public User GetUser(int id)
{
User u = _repository.Get(id);
return u;
}
public User CreateUser(User User)
{
User u = _repository.Create(User);
return u;
}
public List<User> Query(QueryUserRequest request)
{
IQueryable<User> query = _repository.Query();
if (request.Id.HasValue)
{
query = query.Where(User => User.Id == request.Id);
}
if (!string.IsNullOrEmpty(request.UserName))
{
query = query.Where(User => User.UserName == request.UserName);
}
return query.Select(u => new User
{
Id = u.Id,
UserName = h.UserName,
}).ToList();
}
}
Burada service katmanımız mevcut. N-tier mimariyi araştırırsanız service katmanının amacını öğrenebilirsiniz. Konumuz n-tier ve web uygulama mimarisi olmadığı için şimdilik o konunun ayrıntılarına girmiyorum belki başka bir yazımın konusu da bu olur.
Verdiğim örneklerde gördüğünüz gibi, classlarımız bir önceki konum olan http://www.turkhackteam.org/c-j-vb-...ik-konular-dependency-injection-1-ihan3t.html dependency injection metodu ile inject ediliyor.
.Net Core tarafında dependency injection işlemi startup dosyasında ConfigureServices metodu içerisinde yapılıyor.
Örnek olarak :
Kod:
public **** ConfigureServices(IServiceCollection services)
{
services.AddMvc();
services.AddDbContext<MyDbContext>(opt => opt.UseInMemoryDatabase());
services.AddScoped<UserService, UserService>();
services.AddScoped<IRepository<User>, UserRepository>();
}
Artık ihtiyaç durumunda yeni bir db işlemi gerektiğinde sadece UserRepositoryXXX adında bir class oluşturup IRepository interface inden kalıtım alıp, IoC container (ConfigureServices metodu içerisindeki services.AddScope kısmı) bölümünde ismini vermemiz yeterli. Uygulamamız hayatına hiçbir sorun olmadan devam edecektir.
Buraya kadar her şey çok güzel. Fakat bizim başka entity lerimiz de mevcut. Bunların her birisi için aynı işlemi yapan farklı repositoryler mi oluşturacağız?
Hayır. Bu problemi bizim için çöze Generic Repository Pattern e başvuracağız.
Yukarıda gösterdiğim bütün kodlar aynı kalsın. Sadece UserRepository sınıfını aşağıdaki hale getirelim:
Kod:
public class GenericRepository<T> : IRepository<T> where T : class
{
private TurDbContext _context;
private DbSet<T> _dbSet;
public GenericRepository(TurDbContext context)
{
this._context = context;
this._dbSet = context.Set<T>();
}
public T Create(T t)
{
_dbSet.Add(t);
_context.SaveChanges();
return t;
}
public T Get(int id)
{
T t = _dbSet.Find(id);
return t;
}
public IEnumerable<T> List()
{
List<T> list = _dbSet.ToList();
return list;
}
public IQueryable<T> Query(Expression<Func<T, bool>> query)
{
return _dbSet.Where(query);
}
public IQueryable<T> Query()
{
return _dbSet.AsQueryable();
}
public **** Update(T t)
{
_dbSet.Update(t);
_context.SaveChanges();
}
public **** Delete(T t)
{
_dbSet.Remove(t);
_context.SaveChanges();
}
}
UserService sınıfında repository mizi şu şekilde değiştirelim
Kod:
private readonly IRepository<User> _repository;
public UserService(IRepository<User> repository)
{
this._repository = repository;
}
ve dependency injection kısmını şu şekilde değiştirelim:
Kod:
services.AddScoped<IRepository<User>, GenericRepository<User>>();
Artik bu sınıfı her entity için repository olarak kullanabiliriz.
Bizim var olan Product entity miz için bir ProductService yazmak istesek tek yapmamız gereken service sınıfını açıp UserService kodlarının aynısını yazmak ve dependency injection kısmında
Kod:
services.AddScoped<ProductService, ProductService>();
services.AddScoped<IRepository<Product>, GenericRepository<Product>>();
dememiz yeterli. Böylelikle product sınıfı için özel olarak tek satır database sorgusu yapmadan bütün CRUD işlemlerimiz kullanıma hazır halde.
Onlarca entity nesneleriniz olduğunu düşünürsek Generic Repository Pattern bizi oldukça fazla bir iş yükünden kurtarıyor.
Design patternler yazılım dünyasında önemli bir yer kaplıyor. Hele ki kurumsal bir proje üzerinde çalışıyorsanız olmazsa olmazlardandır diyebilirim. Öğrenmek ufkunuzu açacak ve kod yazma standartınızı yükseltecektir emin olun.
Herkese iyi forumlar, ihan3t.
Son düzenleme: