Geçenlerde bir projede veritabanında JSON verilerini yönetmek için uğraşıyordum, bilirsiniz ya o tür karmaşık veri yapıları bazen baş ağrısı yapar. Ben de C# .NET REST API geliştirirken PostgreSQL’e dönmüştüm, çünkü MySQL’e göre JSON desteği daha doğal geliyor bana. Aslında yıllardır Dapper kullanıyorum, hafif ve hızlı olduğu için seviyorum, Entity Framework’ün ağır yükünden kaçınmak adına ideal. Neyse efendim, bu sefer JSON’ları query’lerde nasıl kullanacağımı düşünürken, aklıma eski bir proje geldi, orada hata yapmıştım, veriler karışmıştı.
PostgreSQL’in JSON özelliği gerçekten güçlü, değil mi? Mesela bir tabloya JSON kolonu ekleyip, içinde nested objeler tutabiliyorsun, bu sayede NoSQL gibi esneklik kazanıyorsun relational yapıda. Bana göre bu, modern uygulamalar için vazgeçilmez, özellikle API’lerde dinamik verilerle uğraşırken. Tabi JSONB kullanmak daha iyi, çünkü binary formatta saklanıyor ve index’leme kolaylaşıyor. Sen ne dersin, relational veritabanlarında JSON’a ne kadar yer veriyorsun?
Bu arada, Dapper ile entegre etmek çok basit aslında. Önce Npgsql paketini NuGet’ten yüklemen lazım, PostgreSQL için. Sonra connection string’ini ayarla, ben genelde appsettings.json’da tutuyorum. Evet, bağlantı kurduktan sonra, JSON sorguları için PostgreSQL’in built-in fonksiyonlarını kullanıyorsun, mesela ->> operatörü ile değer çekmek gibi.
Neticede, bir örnek vereyim diyorum, pratik olsun. Diyelim ki users tablosunda profile adında JSON kolonu var, içinde name ve age gibi field’lar. Sorgu şöyle olur: SELECT id, profile->>’name’ AS name FROM users WHERE profile->>’age’ > ’30’; Bunu Dapper ile çağırmak için, bir model class’ı oluşturuyorsun, sonra connection.Query
JSON Veri Ekleme ve Güncelleme
Ekleme kısmına gelince, INSERT INTO users (profile) VALUES (@profile::jsonb); diye yazıyorsun, parametre olarak JSON string’i geçiriyorsun. Dapper’da dynamic parameters ile kolay, var profileJson = JsonSerializer.Serialize(userProfile); sonra new { profile = profileJson }. Aslında PostgreSQL otomatik parse ediyor jsonb’e. Fakat dikkat, büyük verilerde performans düşebilir, o yüzden index koy: CREATE INDEX idx_profile ON users USING gin (profile); Bu gin index JSON için özel, arama hızlanır.
Fakat bazen karışıklık oluyor, mesela nested JSON’da path belirtirken ‘$.key.subkey’ gibi. Ben bir seferinde yanlış path yazdım, veri dönmedi, saatlerce debug yaptım. Neyse efendim, güncelleme için UPDATE users SET profile = profile || @newData::jsonb WHERE id = @id; Bu merge gibi çalışıyor, mevcut JSON’a ekliyor. Pratik değil mi? Sen de kullanıyor musun böyle merge’leri?
(ki bu arada, PostgreSQL docs’unda detaylı örnekler var, PostgreSQL resmi sitesinde bakabilirsin.)
Neden Dapper Tercih Ediyorum?
Dapper’ı seviyorum çünkü micro-ORM, SQL’i kendin yazıyorsun, bu da kontrol veriyor. Entity Framework’te LINQ to SQL bazen beklenmedik query’ler üretiyor, optimizasyon zorlaşıyor. Bana göre Dapper ile PostgreSQL JSON’ları yönetmek, hem hızlı hem güvenli. Tabi security için prepared statements otomatik, injection’a karşı korunaklı. Açıkçası, büyük projelerde bile vazgeçmiyorum ondan.
Şimdi bir kod örneği paylaşayım, C# tarafında. Önce using System.Text.Json; ekle, sonra:
using (var conn = new NpgsqlConnection(connectionString))
{
await conn.OpenAsync();
var sql = “SELECT * FROM users WHERE (profile->>’city’) = @city”;
var users = await conn.QueryAsync<User>(sql, new { city = “Bursa” });
return users.ToList();
}
Bu kadar basit, User class’ında profile string olarak tanımlı, sonra deserialize edersin. Evet gayet güzel çalışıyordu derken, bir keresinde connection pool dolmuştu, timeout alıyordum. Neticede settings’te Max Pool Size artırdım, sorun çözüldü.
Bu arada aklıma geldi, geçen hafta bir forumda benzer sorun tartışılıyordu, Google’da ‘c# dapper postgresql json query examples’ ara, bol örnek çıkar. Sanırım Stack Overflow’da da var, ama tam link hatırlamıyorum.
JSON’ları filter’lamak için advanced query’ler de var, mesela contains operatörüyle: WHERE profile ? ‘key’ gibi, key var mı diye soruyor. Veya @> ile containment check, {age: 30} @> profile->’age’ falan. Karmaşık ama güçlü, veri analizi için ideal. Gerçi ben basit tutuyorum genelde, fazla dallanma olmasın.
Sonuç olarak, C# .NET REST API’lerde PostgreSQL JSON’larını Dapper ile kullanmak, verimliliği artırıyor. Özellikle dinamik form verileri için süper. Tavsiyem, küçük projelerde dene, alışınca vazgeçemezsin. (mağlum performans önemli :))
Bir de şunu ekleyeyim, migration’larda JSON schema validate etmek için extension’lar var, ama ben manuel kontrol ediyorum. Neyse efendim, fazla uzatmayayım.
Bu arada, Microsoft docs’ta C# JSON handling’i incele, faydalı. Ve bir sitede görmüştüm, Dapper contrib paketinde JSON mapper varmış, ama ben vanilla kullanıyorum, gerek görmedim.
Açıkçası ben memnunum bu setup’tan, fakat bazen JSON size limit’ine çarpıyorum, 1GB sınırı var PostgreSQL’de galiba. Sen ne dersin, büyük JSON’lar için ayrı collection mı kullanıyorsun?
Neticede pratik ipucu: Query’lerde AS alias kullan, mapping kolaylaşsın. Evet, profile->>’name’ AS fullName diye.
Şimdi ufak bir sapma yapayım, aklıma geldi, geçenlerde Bursa’da yağmur yağarken kod yazıyordum, odaklanamıyordum, dışarı bakıp dağcılık hayalleri kurdum. Neyse, konuya dönelim.
Güncelleme için bir örnek daha: var updateSql = “UPDATE users SET profile = jsonb_set(profile, ‘{contact,email}’, ‘”‘ + newEmail + ‘”‘) WHERE id = @id”; Dapper ile parametreli yap, string concatenation etme. Güvenli olsun.
(işte böyle bir şey, anladın sen.)
Sonuçta, bu yöntemlerle API’ni zenginleştir, veri modelini esnet. Benim deneyimime göre, PostgreSQL JSON Dapper combo’su uzun vadede kazandırıyor.
Geçen gün kamp yapmaya gittik ailemle Uludağ’a, çadır kurarken aklıma bir devre tasarımı projesi geldi, ama telefonu açmadım, vakit geçirdik güzelce. Neyse, ertesi gün ofise döndüm, o fikirle bir gömülü sistem kartı tasarladım, fakat ilk prototipte I2C bağlantısında hata yaptım, pin’leri karıştırmışım. Win oldu sonunda, debug’layıp düzelttim, şimdi çalışıyor sorunsuz. Ailecek kampın tadı başka tabii, kodlama molası iyi geldi 🙂