Selamlar! Yeni bir blog yazısıyla karşınızdayım. Bu aralar C# ve .NET dünyasında bir hayli vakit geçiriyorum, özellikle REST API geliştirmelerinde hız ve performans benim için çok önemli bir hal aldı. İşte tam da bu noktada, yani veritabanı işlemlerini daha hızlı ve temiz yapmak istediğimde aklıma Dapper geldi. Dapper’ı daha önce kullanmıştım ama sanki yeni başlıyormuşum gibi bir durum söz konusu olunca, hem kendim için bir tekrar hem de sizin için bir başlangıç rehberi hazırlamak istedim.
Şimdi diyeceksiniz ki, ‘Neden Dapper? Entity Framework varken?’ Haklısınız, Entity Framework çok güçlü ve birçok özelliği var. Ama bazen işler biraz daha basite iniyor, daha kontrolü elinde tutmak istiyorsun ve tabii ki performans farkı bariz hissediliyor. Dapper, mikro ORM dediğimiz sınıflandırmanın en bilinenlerinden biri ve gerçekten de işleri inanılmaz kolaylaştırıyor. Yani şey gibi, araba kullanmak yerine bisiklete binmek gibi düşünün; nereye gittiğini daha iyi biliyorsun, daha çok hissediyorsun. 🙂
Peki, bu Dapper denen meret tam olarak nedir derseniz, basitçe SQL sorgularınızın sonucunu doğrudan C# nesnelerinize map’leyen, yani eşleyen bir kütüphane. Kendi yazdığınız SQL sorgularını çalıştırıyorsunuz ve Dapper da sizin için o ham veriyi, yazdığınız model sınıflarına göre dolduruyor. Ne güzel değil mi? Bu sayede hem SQL’in gücünden faydalanıyorsunuz hem de C#’ın tip güvenliğiyle uğraşmış oluyorsunuz.
Şimdi gelelim bu işin kurulumuna ve proje yapısına. Aslında hiç de karmaşık değil, gözünüz korkmasın. Bursa’da benim gibi aktif geliştirme yapanlar bilir, hızlı bir başlangıç yapmak her zaman iyidir. Mesela geçenlerde bir arkadaşım bana sordu, ‘Abi bu Dapper’ı nasıl kuruyoruz, proje yapısı nasıl olmalı?’ diye. Ben de dedim ki, ‘Gel sana anlatayım, hem de bir örnek kodla pekiştirelim.
Öncelikle, Dapper’ı projene eklemen lazım tabi. NuGet Package Manager bunun için var, değil mi? Visual Studio’da projen açıkken, sağ tıkla ‘Manage NuGet Packages…’ de. Sonra ‘Browse’ sekmesinde ‘Dapper’ diye aratıyorsun. Karşına bir sürü şey çıkacak ama sen en üsttekini, official olanı seçiyorsun ve install diyorsun. İşte bu kadar basit. Yani, aslında kurulumu dediğim gibi 2 dakika sürüyor sanırım. (ki bence bu çok önemli)
Kurulum bittiğine göre, şimdi projede nasıl kullanacağımıza bakalım. Genelde ben şöyle yaparım: Veritabanı bağlantılarını yönetmek için ayrı bir katman veya klasör oluştururum. Mesela ‘DataAccess’ gibi bir isim verebilirsin. Bu katmanın içinde de veritabanı işlemlerini yapacak sınıflar olur. Mesela ‘UserRepository’, ‘ProductRepository’ gibi. Bu repository sınıfları, Dapper’ı kullanarak direkt SQL sorgularını çalıştırır.
Hani bazen kod yazarken şöyle bir şey olur ya, ‘Acaba doğru mu yapıyorum?’ diye şüpheye düşersin. İşte o şüpheleri gidermek için size şöyle bir örnek kod vereyim. Diyelim ki bir kullanıcı listesi çekeceğiz. Önce yanlış bir yaklaşımla başlayalım, sonra da Dapper ile doğru ve temiz halini görelim.
Önceki zamanlarda, belki de Dapper’ı ilk kullanmaya başladığımda, şöyle bir hata yapmıştım. Direkt bağlantı string’ini sorgunun içine gömmek gibi. Yani, kodun içinde bağlantı bilgilerini de tutuyordum, ki bu hiç güvenli değil. Tabii ki şimdi o kodları göstermeyeceğim ama konsepti anlamak için şöyle bir şey hayal edelim:
// YANLIŞ YAKLAŞIM (Örnek – Gerçek Koddaki Hata)
using System.Data.SqlClient; // Veya Npgsql, MySql vb. using System.Collections.Generic; using System.Threading.Tasks;public class WrongUserRepository { public async Task> GetAllUsersAsync() { var users = new List(); // Bağlantı bilgileri direkt kod içinde, KÖTÜ BİR ALISKANLIK! string connectionString = "Server=myServerAddress;Database=myDataBase;User Id=myUsername;Password=myPassword;"; using (var connection = new SqlConnection(connectionString)) { await connection.OpenAsync(); var command = new SqlCommand("SELECT Id, Name, Email FROM Users", connection); var reader = await command.ExecuteReaderAsync(); while (await reader.ReadAsync()) { // Manuel map'leme, hem yorucu hem hata yapmaya müsait users.Add(new User { Id = reader.GetInt32(0), Name = reader.GetString(1), Email = reader.GetString(2) }); } } return users; } }
Gördünüz mü? Hem bağlantı string’i orada duruyor, hem de her bir sütunu tek tek okuyup nesneye atamakla uğraşıyoruz. Bu, hem zaman kaybı hem de bir hata yakalanana kadar kodun çalışmasını engelleyebilir. Yani şey gibi, bir resmi çizeceksin ama fırçayı kendin yapıyorsun, boyayı kendin karıştırıyorsun falan. Biraz fazla zahmetli değil mi?
Şimdi gelelim Dapper ile bu işi nasıl daha temiz ve profesyonel yapacağımıza. İşte burada Dapper’ın asıl sihri ortaya çıkıyor. Kendi SQL sorgunu yazıyorsun ve Dapper o sorgunun sonucunu doğrudan senin model sınıfına map’liyor. Ne kadar güzel değil mi?
// DOĞRU YAKLAŞIM (Dapper ile)
using Dapper; // Dapper'ı kullandığımızı belirtiyoruz using Microsoft.Extensions.Configuration; // Configuration'dan bağlantı string'ini almak için using System.Collections.Generic; using System.Data; // IDbConnection için using System.Threading.Tasks;// Bağlantı string'ini Configuration'dan alacağımız varsayımıyla public class UserRepository { private readonly IConfiguration _configuration; // Dependency Injection ile gelecek
public UserRepository(IConfiguration configuration) { _configuration = configuration; }
private IDbConnection GetConnection() { // Burada kendi veritabanı tipine göre (SqlConnection, NpgsqlConnection vb.) // bağlantı nesnesini oluşturabilirsin. // Ben örnek olarak SqlConnection kullanıyorum ama sen PostgreSQL için NpgsqlConnection kullanabilirsin. return new System.Data.SqlClient.SqlConnection(_configuration.GetConnectionString("DefaultConnection")); }
public async Task> GetAllUsersAsync() { using (var connection = GetConnection()) { // Kendi yazdığımız SQL sorgusu string sql = "SELECT Id, Name, Email FROM Users"; // Dapper'ın QueryAsync metodu, sorguyu çalıştırır ve sonucu User listesine map'ler. return await connection.QueryAsync(sql); } } }
// Model sınıfımız (basit bir örnek) public class User { public int Id { get; set; } public string Name { get; set; } public string Email { get; set; } }
Bakın şimdi, ne kadar fark var değil mi? Hem bağlantı bilgisi Configuration’dan alınıyor, hem de tüm o manuel map’leme işi yok. `connection.QueryAsync
Bu arada, Dapper’ın sadece sorgu çekmekle kalmadığını da belirtmek lazım. Insert, Update, Delete işlemleri için de `ExecuteAsync` gibi metodları var. Yani aslında tüm CRUD operasyonlarını Dapper ile gayet rahat bir şekilde halledebiliyorsun. Hani bazen bir projede 100 tane küçük tablo varsa ve her biri için ayrı ayrı Entity Framework model sınıfı oluşturmak istemiyorsan, Dapper’la kendi yazdığın sorgularla direkt işlemi yapabilirsin. Bu da projenin daha hafif olmasını sağlar. Sonuç olarak, Dapper gerçekten de hız ve kontrol isteyen projeler için harika bir seçenek. Denemeyenlere kesinlikle tavsiye ederim, pişman olmazsınız bence. 🙂 Belki bir sonraki yazımda Dapper’ın stored procedure kullanımı veya transaction yönetimi gibi konularına da değinebilirim, ne dersin?
Eğer Dapper ile ilgili daha fazla bilgi edinmek istersen, Google’da Dapper ORM diye aratıp bolca kaynağa ulaşabilirsin. Hatta GitHub’da da Dapper’ın kendi sayfasında detaylı dokümantasyonlar mevcut. Dapper GitHub linkine de buradan ulaşabilirsin. Kendi denemelerimden anladığım kadarıyla, bu kütüphane özellikle performansın kritik olduğu yerlerde süper işler başarıyor. Yani aslında bu kadar basit bir kurulumla böylesine güçlü bir araca sahip olmak harika.
Neyse efendim, bugünlük bu kadar. Umarım Dapper’ın ne kadar kullanışlı olduğunu anlatabilmişimdir. Kendi projelerinizde denemenizi şiddetle tavsiye ederim. Hadi bakalım, kolay gelsin herkese!