Furkan KapukayaYazılım geliştirme
C# ve .NET3 dk okuma

C# LINQ Rehberi: Where, Select, GroupBy ve Performans İpuçları

C# LINQ sorgularının temel operatörleri, ertelenmiş çalıştırma, Entity Framework ile kullanımı, sık yapılan performans hataları ve örnek kodlar.

LINQ (Language Integrated Query), C# içinde koleksiyonlar, veritabanları ve diğer veri kaynakları üzerinde tutarlı bir sözdizimiyle sorgu yazmayı sağlayan özelliktir. Doğru kullanıldığında kodu kısaltır ve okunabilirliği artırır; yanlış kullanıldığında ise fark edilmeyen performans sorunlarına yol açabilir.

Temel operatörler

Aşağıdaki örneklerde basit bir ürün listesi kullanalım:

record Urun(int Id, string Ad, string Kategori, decimal Fiyat, int Stok);

var urunler = new List<Urun>
{
    new(1, "Klavye", "Aksesuar", 750m, 12),
    new(2, "Monitör", "Ekran", 6500m, 3),
    new(3, "Fare", "Aksesuar", 400m, 0),
    new(4, "Dizüstü", "Bilgisayar", 32000m, 5)
};

Where: filtreleme

var stoktakiler = urunler.Where(u => u.Stok > 0);

Select: dönüştürme

var adlar = urunler.Select(u => u.Ad.ToUpper());

OrderBy / ThenBy: sıralama

var sirali = urunler.OrderBy(u => u.Kategori).ThenByDescending(u => u.Fiyat);

GroupBy: gruplama

var kategoriToplam = urunler
    .GroupBy(u => u.Kategori)
    .Select(g => new { Kategori = g.Key, Adet = g.Count(), StokDegeri = g.Sum(u => u.Fiyat * u.Stok) });

Any, All, Count

bool tukenenVar = urunler.Any(u => u.Stok == 0);
bool hepsiPozitif = urunler.All(u => u.Fiyat > 0);

First, FirstOrDefault, Single

First eleman bulunamazsa hata fırlatır, FirstOrDefault varsayılan değer döner. Single ise tam olarak bir eleman bekler. Bulunamama ihtimali varsa FirstOrDefault kullanın.

Ertelenmiş çalıştırma (deferred execution)

LINQ sorgularının çoğu tanımlandığı anda değil, sonuçları okunduğunda çalışır:

var sorgu = urunler.Where(u => u.Fiyat > 1000); // henüz çalışmadı
foreach (var u in sorgu) { /* şimdi çalıştı */ }

Aynı sorguyu birden fazla kez dolaşırsanız her seferinde yeniden çalışır. Sonucu tekrar kullanacaksanız ToList() ile bir kez somutlaştırın.

Entity Framework ile LINQ

Entity Framework Core, LINQ ifadelerini SQL sorgusuna çevirir. Burada IQueryable ve IEnumerable farkı kritik önemdedir. Temeller için Entity Framework Core nedir yazımıza bakabilirsiniz.

// Doğru: filtre SQL'e çevrilir, veritabanında çalışır
var pahali = await db.Urunler.Where(u => u.Fiyat > 1000).ToListAsync();

// Yanlış: tüm tablo belleğe çekilir, filtre uygulamada çalışır
var pahali2 = db.Urunler.ToList().Where(u => u.Fiyat > 1000);

Sık yapılan performans hataları

  1. Erken ToList(): Filtrelemeden önce tüm veriyi belleğe almak.
  2. Gereksiz sütun çekmek: Yalnızca ihtiyaç duyulan alanları Select ile seçin.
  3. Döngü içinde sorgu (N+1): Her kayıt için ayrı sorgu atmak yerine ilişkili verileri tek sorguda alın.
  4. Count() > 0 yerine Any(): Varlık kontrolü için Any() daha anlamlı ve çoğu zaman daha verimlidir.
  5. Salt okunur sorgularda takip: EF Core'da yalnızca okuma yapılacaksa AsNoTracking() kullanın.
  6. Sayfalama yapmamak: Büyük listelerde Skip ve Take ile sayfalama yapın.

Veritabanı tarafındaki iyileştirmeler için SQL Server performansı yazısı da faydalı olacaktır.

Okunabilirlik önerileri

  • Uzun zincirleri her operatör ayrı satırda olacak şekilde biçimlendirin.
  • Karmaşık koşulları anlamlı isimli metotlara taşıyın.
  • Anonim tipler yerine, sonuç dışarı aktarılacaksa record veya DTO kullanın.

Sık sorulan sorular

Sorgu sözdizimi mi, metot sözdizimi mi?

İkisi aynı sonucu üretir. Metot sözdizimi daha yaygın kullanılır; birleştirme (join) ağırlıklı sorgularda sorgu sözdizimi daha okunaklı olabilir.

LINQ yavaş mıdır?

Bellek içi koleksiyonlarda çoğu senaryo için yeterince hızlıdır. Performans sorunları genellikle LINQ'nun kendisinden değil, yanlış kullanımdan kaynaklanır.

Sonuç

LINQ, C# geliştiricisinin en güçlü araçlarından biridir. Temel operatörleri, ertelenmiş çalıştırmayı ve EF Core ile doğru kullanımı öğrendiğinizde hem daha kısa hem de daha performanslı kod yazarsınız. .NET projelerinizde destek için iletişime geçebilirsiniz.