Blog
Mert Özen'in yazılım geliştirme, backend, frontend ve DevOps üzerine blog yazıları.
Toplu Import ve Validation Raporu: Excel/CSV Yükle, Staging Tablosu, Satır Bazlı Hata Dosyası
Büyük ve kirli bir Excel/CSV dosyasını güvenle içeri almanın yolu, dosyayı metin kolonlu bir staging tablosuna SqlBulkCopy ile yüklemek, kuralları set-based SQL ile her satıra uygulamak, kullanıcıya satır bazlı hata dosyası vermek ve commit'i onayla ayrı bir adımda yapmaktır. Bu yazı 202 Accepted + durum endpoint'i, dosya hash'iyle idempotency ve CSV injection'a karşı escape ile 20.000 satırlık bir importu gerçek çıktılarla gösteriyor.
Pagination Stratejileri Derinlemesine: Offset, Keyset ve Opaque Cursor Token
Büyük ve değişen tablolarda keyset pagination, offset'in derinlikle artan maliyetini ve sayfa kaymasını ortadan kaldırır: 2 milyon satırlık testte 5000. sayfa offset ile 375, keyset ile 6 logical read okudu. Bu yazı SQL Server'da tie-breaker'lı keyset koşulunu, HMAC ile imzalı opaque cursor'ı, önceki sayfayı ve nullable sıralama kolonu tuzağını gerçek ölçümlerle gösteriyor.
Optimistic Concurrency Uçtan Uca: rowversion'dan ETag'e, If-Match ve 412 ile Çakışma Ekranı
Optimistic concurrency'yi web'de uçtan uca kurmak için rowversion'ı ETag olarak dışarı açmak, güncellemede If-Match'i zorunlu tutmak (yoksa 428), uyuşmazlıkta 412 ile güncel değerleri dönmek ve istemcide field bazlı three-way merge yapmak gerekir. Bu yazı EF Core Concurrency yazısının devamı olarak HTTP ve Angular tarafını gerçek çıktılarla gösteriyor.
Idempotency Key: Çift Tıklama ve Retry'da Aynı Siparişi İki Kez Oluşturmamak
Çift tıklama ve retry'da aynı siparişin iki kez oluşmasını engellemenin güvenilir yolu, istemcinin her işlem için ürettiği bir Idempotency-Key'i sunucunun kullanıcı scope'unda, request hash'iyle birlikte saklaması ve iş ile 'tamamlandı' kaydını aynı transaction'da yazmasıdır. Bu yazı IETF taslağının güncel durumunu (draft-08, RFC değil), 400/409/422 kurallarını ve ASP.NET Core endpoint filter + SQL Server uygulamasını gerçek çıktılarla gösteriyor.
Zaman ve Time Zone: UTC Instant, Yerel İş Günü, DateOnly ve TimeProvider
Zamanı doğru saklamak için üç kavramı ayırmak gerekir: event anları UTC instant (DateTimeOffset), takvim günleri DateOnly, gelecekteki yerel event'ler wall-clock time ve IANA zone id'si olarak saklanır. Bu yazı tenant'ın gününü UTC aralığına çevirmeyi, TimeProvider ile test edilebilir saati, SQL Server'daki AT TIME ZONE tuzaklarını ve Angular'daki tarih kaymasını gerçek çıktılarla gösteriyor.
Para ve Yuvarlama: decimal, Money Value Object, KDV ve Kuruş Dağıtımı
Parayı doğru modellemek için tutarı para birimiyle birlikte taşıyan bir Money value object, C# ile SQL'de aynı açık yuvarlama kuralı ve bölme yerine kuruşu kaybetmeyen Allocate gerekir. Yazı Math.Round ile SQL ROUND'un 0,125'te ayrıştığını, satır ve toplam bazında KDV'nin 1 kuruş farkını, tarihli KDV oranı tablosunu (Kasım 2026 itibarıyla %20, %10, %1), EF Core complex type mapping'ini ve JSON'da string tutarı gerçek çıktılarla gösteriyor.
Numaralandırma: Fatura ve Sipariş Numaraları, Gapless Sequence ve Yıllık Sıfırlama
Ardışık olması gereken fatura numarası identity, MAX + 1 ya da SEQUENCE ile değil, onay transaction'ının içinde (Series, Year) key'li bir counter tablosundan lock alan bir UPDATE ile alınmalıdır; boşluk kabul edilen sipariş numaraları için SEQUENCE yeterlidir. Yazı GİB'in 16 karakterlik belge numarası biçimini, 50 concurrent onayla boşluksuzluğu, lock süresinin throughput'a etkisini ve fatura tarihine göre yıllık sıfırlamayı gerçek çıktılarla gösteriyor.
Feature Flag'leri Kodda Tasarlamak: Toggle Türleri, Microsoft.FeatureManagement ve Flag Borcu
Feature flag'i doğru tasarlamak, önce türünü (release, experiment, ops, permission) belirlemek, kararı tek bir toggle router'da toplamak ve her flag'e sahip ile son kullanma tarihi vermektir. Yazı Microsoft.FeatureManagement 4.8.0 ile tenant filter'ı, snapshot ile istek içi tutarlılığı, WithFeatureGate ile kill switch'i ve süresi geçen flag'i yakalayan testi gerçek çıktılarla gösteriyor.
Settings Tabloları: Global → Tenant → Kullanıcı Override Hiyerarşisi
Çalışırken değişen, tenant ve kullanıcıya göre ezilen ayarlar için en sağlam yol, her ayarın tip, varsayılan, aralık ve en alt override seviyesini taşıyan bir tanımı ile bu tanıma bağlı tipli key-value değerlerdir; öncelik kuralı tek bir service'te, yazma doğrulamalı ve audit'li olur. Yazı EAV, tipli kolonlar, JSON belge ve dış store ile karşılaştırıyor ve EF Core'un nullable unique index'e eklediği gizli IS NOT NULL filtresini gösteriyor.
Multi-Tenancy'de Veri İzolasyonu: Database-per-Tenant, Shared Schema ve Row-Level Security
Çoğu SaaS için en iyi denge, TenantId kolonlu paylaşılan tablolar, EF Core'da named bir tenant query filter'ı ve onun arkasında SESSION_CONTEXT ile beslenen SQL Server row-level security'dir. Yazı database-per-tenant, schema-per-tenant ve shared table modellerini karşılaştırıyor; tenant çözümlemeyi, background job'ları ve izolasyonu otomatik test etmeyi gerçek çıktılarla gösteriyor.
Çok Dilli Veri: Ürün Adını TR ve EN Saklamak — Translation Table, JSON Kolon ve Fallback
Kullanıcının yönettiği çok dilli veri için en esnek seçenek, (EntityId, Culture, Name) key'li bir translation tablosu ve en-GB → en → tr gibi tek yerde kurulan bir fallback zinciridir. Yazı dil başına kolon, translation tablosu, SQL Server 2025 json kolonu ve ayrı bir translation service'i karşılaştırıyor; EF Core 10 LeftJoin ile fallback'i ve Türkçe I için collation seçimini gerçek çıktılarla gösteriyor.
Polymorphic Association: Yorum ve Ek Dosyaları Birden Fazla Tabloya Bağlamak
Ek dosyayı EntityType/EntityId çiftiyle birden çok tabloya bağlamak FK'yı, cascade delete'i ve güvenli yetkilendirmeyi kaybettirir; sahip tipleri az ve kararlıysa her sahip için nullable FK ve tam olarak birini zorunlu kılan check constraint'li exclusive arc kullan. Yetkiyi ekin kendisinden değil sahibinin policy'sinden türet.