Merhaba günümüz dünyasının yavaş yavaş popüler olmaya başlayan patternlerinden olan CQRS yani "Command Query Responsibilty Segregation" isminden bahsedeceğim. Bu patterni kısaca özetleyecek olursak şöyle başlamak istiyorum. Aşağıdaki resme ilk olarak göz atmanızı istiyorum.
Bu pattern resimden anlaşılacağı üzere Command ve Query yapılarının üzerinden oluşmaktadır. Add, Update, Delete gibi işlemleri Command üzerinden Get, GetById vb. read işlemlerini ise Query yapısının üzerinden oluşturulmaktadır. Dilerseniz bunu bir projeyle bahsedeyim.
İlk olarak ben Northwind örnek databasesini kullandım. Sizde bunu rahatlıkla Google'dan ulaşıp üzerine çalışabilirsiniz. Haydi başlayalım. Şimdi bir entity classı oluşturmak için Product.cs classını oluşturuyorum ve propları şu şekilde tanımlıyorum.
public class Product : IEntity
{
public int ProductID { get; set; }
public string ProductName { get; set; }
public int SupplierID { get; set; }
public int CategoryID { get; set; }
public string QuantityPerUnit { get; set; }
public decimal UnitPrice { get; set; }
public int UnitsInStock { get; set; }
public int Discontinued { get; set; }
}
Devamında ise Northwind database ile bağlantıyı kurmak için EntityFramework.Core paketini projeme dahil ettim ve sonra bir DbContext oluşturdum.
public class CQRSDatabaseContext : DbContext
{
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseSqlServer(@"Server=
(localdb)\MSSQLLocalDB;Database=Northwind;integrated security=true;");
}
public DbSet<Product> Products { get; set; }
}
Bu adımdan sonra bu contexi oluşturduğum katmanda migration ekleyip "dotnet ef migrations add DbConnect" komutuyla database bağlantımı gerçekleştiriyorum. Burada dikkat etmeniz gereken EntityFrameworkCore'nin SqlServer ve Design paketlerini de ekstradan yüklemeniz gerekmektedir. Bu aşamaya kadar toparlayacak olursak kısaca database ile bağlantımızı sağladık. Şimdi asıl kısma gelelim.
CQRS içinde Mediator Pattern'ede giriş yapacağız bu patternide size kısaca özetleyecek olursam klasik uçak örneğini vereceğim. Bir çok uçak havada uçarken birbiriyle iletişime geçmeyip direkt kuleyle iletişime geçerler. Kuleyle olan iletişimleri sayesinde uçaklar rahatlıkla iniş ve kalkışlarını sağlarlar. Kendi aralarında iletişime geçmeye çalışsalar bir kargaşa olur işte Mediator Pattern'de tam olarak burada bahsettiğim kuledir. Şimdi gelelim CQRS'ye..
İlk olarak Command, Handler ve Query olmak üzere 3 klasörleme yapalım ve devamında ilk olarak bir GetAll işlemi yapmak için read olacağından Query klasörüne gidip Request ve Response adında iki klasör daha oluşturalım.Kısaca yapımız şu şekilde olacaktır.
Şimdi bir product için GetAll servisi yazalım bunun için ilk olarak MediatR ve MediatR Dependency Injection paketini kuralım, bu paketleri ileride oluşturacağımız Startup.cs classında eklememiz gerekmektedir, sonra Queries>Response klasörüne gidip "GetAllProductQueryResponse" adı altında bir class oluşturalım ve burada bize dönmesini istediğimiz propertyleri tanımlayalım.
public class GetAllProductQueryResponse
{
public int ProductID { get; set; }
public string ProductName { get; set; }
public int CategoryID { get; set; }
public decimal UnitPrice { get; set; }
}
Daha sonra request atacağımız class olan "GetAllProductQueryRequest" classını oluşturuyoruz ve MediatR paketinden gelen IRequest interfacesini burada kullanıyoruz.
public class GetAllProductQueryRequest:IRequest<List<GetAllProductQueryResponse>>
{
}
Buraya kadar yaptığımız yapı request ve response querylerini oluşturmaktı. Şimdi ise QueryHandler'ı oluşturmaya sıra geldi. Burada ise direkt sorgularımızı yazacağımız ve istediğimiz veriyi db den çekeceğimiz kısımı oluşturmaktadır. "GetAllProductQueryHandler" adında bir class oluşturuyoruz ve IRequestHandler interfacesini MediatR paketinden çağırıyoruz.
public class GetAllProductQueryHandler : IRequestHandler<GetAllProductQueryRequest, List<GetAllProductQueryResponse>>
{
private CQRSDatabaseContext _db = new CQRSDatabaseContext();
public async Task<List<GetAllProductQueryResponse>> Handle(GetAllProductQueryRequest request, CancellationToken cancellationToken)
{
var result = _db.Products.Select(product => new GetAllProductQueryResponse
{
ProductID = product.ProductID,
CategoryID = product.CategoryID,
UnitPrice = product.UnitPrice,
ProductName = product.ProductName
});
return result.ToList();
}
}
Veee.. Son adıma geliyoruz Asp.Net Core Web API oluşturup ProductsController oluşturuyoruz. MediatR kütüphanesinin constructorını controllerımıza yazıyoruz ve klasik Get methodunu yazıyoruz.
public class ProductsController : ControllerBase
{
private IMediator _mediator;
public ProductsController(IMediator mediator)
{
_mediator = mediator;
}
[HttpGet("GetAll")]
public async Task<IActionResult> GetAllProduct([FromQuery] GetAllProductQueryRequest model)
{
List<GetAllProductQueryResponse> products = await _mediator.Send(model);
return Ok(products);
}
}
Swagger entegrasyonunu sağladıktan sonra komutu çalıştırıyoruz ve sonucu başarılı bir şekilde alıyoruz..
Id'ye göre ürün getirme ve ekleme işlemlerinde projeye dahil ettim. Sizde geliştirip üzerinde çalışabilirsiniz. Projeyi github hesabınızdan beğendiyseniz yıldızlamayı lütfen unutmayınız.. Kolay gelsin.
Proje GitHub Kaynak Kod