LINQ Performans İyileştirme ve Gelişmiş Kullanım Teknikleri

Gelişmiş LINQ Kullanımı: Performans ve Etkinlik İçin Derinlemesine Bir İnceleme

Önceki makalemizde “LINQ (Language Integrated Query) Expressions” başlığı altında LINQ teknolojisinin temellerini ve basit sorgulama yöntemlerini ele almıştık.

Bu yeni yazımızda ise bir adım ileri gidiyoruz: LINQ kullanırken performansı artırmaya yönelik teknikler, gerçek dünya senaryolarında en doğru kullanım biçimleri ve yaygın yapılan hatalara karşı alınabilecek önlemler üzerine odaklanacağız.

LINQ sorgularında performans optimizasyonu, doğru sorgu tasarımı, veri tabanı yönetimi ve ileri seviye kullanım ipuçlarıyla daha hızlı, daha verimli uygulamalar geliştirmek için gereken tüm detayları bu rehberde bulabilirsiniz.

Şimdi LINQ dünyasında daha derin bir keşfe çıkalım.

İçindekiler

Verimix Blog - Linq query

1. Performans Optimizasyonu

1.2. Gereksiz Veri Getirme

Yanlış Kullanım: Gereksiz tüm sütunları sorguya dahil etmek.

				
					var products = context.Products.ToList(); // Tüm sütunlar getirilir
				
			

İdeal Kullanım: Sadece gerekli sütunları projekte edin.

				
					var productNames = context.Products
    .Select(p => new { p.Name, p.Price })
    .ToList();

				
			

1.2. Eager Loading ve Lazy Loading’i Yanlış Yönetmek

❌ Yanlış Kullanım: Gereksiz Include kullanımıyla fazla veri yüklemek.

				
					var orders = context.Orders
    .Include(o => o.Customer)
    .Include(o => o.Products)
    .ToList();

				
			

İdeal Kullanım: İhtiyaç duyulan veriler için Include kullanın.

				
					var orders = context.Orders
    .Include(o => o.Products)
    .Where(o => o.OrderDate > DateTime.UtcNow.AddMonths(-1))
    .ToList();

				
			

1.3. N+1 Sorgu Problemini Göz Ardı Etmek

❌ Yanlış Kullanım: İlgili veriler için ayrı sorgular çalıştırmak.

				
					var customers = context.Customers.ToList();
foreach (var customer in customers)
{
    var orders = context.Orders.Where(o => o.CustomerId == customer.Id).ToList();
}

				
			

İdeal Kullanım: İlgili verileri tek bir sorguda getirin.

				
					var customersWithOrders = context.Customers
    .Include(c => c.Orders)
    .ToList();

				
			

1.4. Filtrelemeyi Bellek Tarafında Yapmak

❌ Yanlış Kullanım: Tüm veriyi bellek içinde filtrelemek.

				
					var orders = context.Orders.ToList();
var recentOrders = orders.Where(o => o.OrderDate > DateTime.UtcNow.AddMonths(-1));

				
			

İdeal Kullanım: Filtrelemeyi veritabanı tarafında yapın.

				
					var recentOrders = context.Orders
    .Where(o => o.OrderDate > DateTime.UtcNow.AddMonths(-1))
    .ToList();

				
			

1.5. Indeksleri Göz Ardı Etmek

❌ Yanlış Kullanım: Sorgular için uygun indekslerin olmaması.

				
					SELECT * FROM Orders WHERE CustomerId = 123;
-- Bu sorgu indeks yoksa yavaş çalışabilir.
				
			

İdeal Kullanım: Sık kullanılan sütunlar için indeksler oluşturun.

				
					CREATE INDEX IX_Orders_CustomerId ON Orders (CustomerId);
				
			

1.6. Çok Fazla İzleme (Tracking)

❌ Yanlış Kullanım: Gereksiz izleme (tracking) ile kaynak tüketimini artırmak.

				
					var products = context.Products.ToList(); // Tracking açık
products[0].Price = 10; // Değişiklik takibi yapar

				
			

İdeal Kullanım: Sorguları izleme olmadan çalıştırın.

				
					var products = context.Products.AsNoTracking().ToList();
				
			

1.7. Transaction Kullanımını İhmal Etmek

❌ Yanlış Kullanım: Çoklu veri tabanı işlemlerini transaction olmadan gerçekleştirmek.

				
					context.Products.Add(new Product { Name = "Product1" });
context.SaveChanges();
context.Orders.Add(new Order { ProductId = 1, Quantity = 10 });
context.SaveChanges();

				
			

İdeal Kullanım: Tüm işlemleri bir transaction içinde yürütün.

				
					using var transaction = context.Database.BeginTransaction();
context.Products.Add(new Product { Name = "Product1" });
context.SaveChanges();
context.Orders.Add(new Order { ProductId = 1, Quantity = 10 });
context.SaveChanges();
transaction.Commit();

				
			

1.8. First ve Single Kullanımını Yanlış Yönetmek

❌ Yanlış Kullanım: Veri bulunamaması durumunda hata veren First veya Single kullanmak.

				
					var item = context.Data.First(d => d.Id == 1); // Veri yoksa hata fırlatır
				
			

İdeal Kullanım: Güvenli sorgulamalar için FirstOrDefault veya SingleOrDefault kullanın.

				
					var item = context.Data.FirstOrDefault(d => d.Id == 1);
if (item == null)
{
    Console.WriteLine("Veri bulunamadı.");
}	

				
			

2. LINQ Kullanım Türleri

2.1. Entitiy Framework Üzerinde Kullanımı

2.1.1. Where

Where metodu, belirtilen bir koşulu karşılayan öğeleri seçer.

				
					List<Product> products = new List<Product>
        {
            new Product { Name = "Laptop", Price = 1500, InStock = true, Category = "Bilgisayar" },
            new Product { Name = "Mouse", Price = 150, InStock = true, Category = "Elektronik" },
            new Product { Name = "Klavye", Price = 90, InStock = true, Category = "Elektronik" },
            new Product { Name = "Masa", Price = 300, InStock = false, Category = "Mobilya" },
            new Product { Name = "Telefon", Price = 450, InStock = true, Category = "Elektronik" }
        };

        var filteredProducts = products.Where(p => 
            p.Price >= 100 && 
            p.Price <= 500 && 
            p.InStock && 
            (p.Category == "Elektronik" || p.Category == "Bilgisayar")
        );
// Ürün listesinden fiyatı 100 ile 500 arasında olan, stokta bulunan ve kategorisi "Elektronik" veya "Bilgisayar" olan ürünleri süzüp yeni bir koleksiyon oluşturur.

				
			
2.1.2. Select & SelectMany

Select: Koleksiyon öğelerini dönüştürür.

SelectMany: Koleksiyonun her bir öğesi için yeni koleksiyonlar döndürür ve bunları birleştirir.

				
					var authors = new List<Author>
{
    new Author { Name = "John", Books = new List<string> { "C# 101", "LINQ Deep Dive" } },
    new Author { Name = "Jane", Books = new List<string> { "ASP.NET Core", "Blazor Basics" } }
};

var allBooks = authors.SelectMany(a => a.Books.Select(book => $"{a.Name}: {book}")).ToList();
// Yazar adı ve kitap adı birleştirilerek düz bir liste elde ediliyor.

				
			
2.1.3. First & FirstOrDefault

First: Koleksiyonda belirtilen koşulu karşılayan ilk öğeyi döndürür. Eğer öğe yoksa hata fırlatır.

FirstOrDefault: Koşulu karşılayan ilk öğeyi döndürür, eğer öğe yoksa varsayılan değeri döndürür.

				
					var orders = new List<Order>
{
    new Order { Id = 1, Status = "Pending" },
    new Order { Id = 2, Status = "Shipped" }
};

var firstShipped = orders.FirstOrDefault(o => o.Status == "Shipped") ?? new Order { Id = 0, Status = "None" };
// Belirli bir durumdaki ilk siparişi buluyor, yoksa varsayılan değer dönüyor.

				
			
2.1.4. Single & SingleOrDefault

Single: Koleksiyonda sadece bir öğe varsa onu döndürür, yoksa hata fırlatır.

SingleOrDefault: Koleksiyonda yalnızca bir öğe varsa onu döndürür, yoksa varsayılan değeri döndürür.

				
					var users = new List<User> { new User { Email = "test@example.com" } };
var uniqueUser = users.SingleOrDefault(u => u.Email == "test@example.com");
// Sadece bir tane eşleşme varsa döner.

				
			
2.1.5. OrderBy & ThenBy

OrderBy: Öğeleri artan sırayla sıralar.

OrderByDescending: Öğeleri azalan sırayla sıralar.

				
					var employees = new List<Employee>
{
    new Employee { Name = "Ali", Age = 30 },
    new Employee { Name = "Ayşe", Age = 25 },
    new Employee { Name = "Ali", Age = 28 }
};

var ordered = employees.OrderBy(e => e.Name).ThenBy(e => e.Age);
// İlk isme, sonra yaşa göre sıralama yapılıyor.

				
			
2.1.6. GroupBy

Öğeleri belirli bir kritere göre gruplar.

				
					var sales = new List<Sale>
{
    new Sale { Region = "Europe", Year = 2024, Amount = 5000 },
    new Sale { Region = "Europe", Year = 2025, Amount = 7000 },
    new Sale { Region = "Asia", Year = 2024, Amount = 6000 }
};

var grouped = sales.GroupBy(s => new { s.Region, s.Year })
                   .Select(g => new { g.Key.Region, g.Key.Year, Total = g.Sum(x => x.Amount) });
// Bölge ve yıla göre gruplama yapılıyor.

				
			
2.1.7. Join

Bir koleksiyonu başka bir koleksiyonla belirli bir anahtar üzerinden birleştirir.

				
					var students = new List<Student>
{
    new Student { Id = 1, Name = "Ali", ClassId = 101 },
    new Student { Id = 2, Name = "Veli", ClassId = 102 }
};

var classes = new List<Class>
{
    new Class { Id = 101, Name = "Physics" },
    new Class { Id = 102, Name = "Chemistry" }
};

var schools = new List<School>
{
    new School { ClassId = 101, SchoolName = "Science High" },
    new School { ClassId = 102, SchoolName = "Tech Academy" }
};

var result = students
    .Join(classes, s => s.ClassId, c => c.Id, (s, c) => new { s.Name, c.Name, c.Id })
    .Join(schools, sc => sc.Id, sch => sch.ClassId, (sc, sch) => new { sc.Name, sc.Name, sch.SchoolName });
// Öğrenci -> Sınıf -> Okul çoklu join yapılıyor.

				
			
2.1.8. Any & All

Any: Koleksiyonda belirtilen koşulu karşılayan herhangi bir öğe varsa true döndürür.

All: Koleksiyondaki tüm öğeler belirtilen koşulu karşılıyorsa true döndürür.

				
					List<Product> products = new List<Product>
        {
            new Product { Name = "Laptop", Category = "Bilgisayar", Brand = "Asus" },
            new Product { Name = "Telefon", Category = "Elektronik", Brand = "Samsung" },
            new Product { Name = "Klavye", Category = "Elektronik", Brand = "Logitech" },
            new Product { Name = "Masa", Category = "Mobilya", Brand = "Ikea" }
        };

        List<string> favoriteCategories = new List<string> { "Elektronik", "Kitap" };
        List<string> favoriteBrands = new List<string> { "Logitech", "Apple" };

        bool hasMatch = products.Any(p =>
            favoriteCategories.Any(favCat => favCat == p.Category) &&
            favoriteBrands.Any(favBrand => favBrand == p.Brand)
        );
// Ürünler listesinde kategorisi favori kategorilerden biriyle ve markası favori markalardan biriyle birebir eşleşen en az bir ürün olup olmadığını kontrol eder.

bool allFavoriteCategoriesExist = favoriteCategories.All(favCat =>
            products.Any(p => p.Category == favCat)
        );
// Kullanıcının favori kategorilerinin hepsi için ürün listesinde en az bir ürün bulunuyor mu kontrolü

				
			
2.1.9. Count & Sum & Avarage

Count: Koleksiyondaki öğelerin sayısını döndürür.

Sum: Koleksiyondaki sayıları toplar.

Average: Koleksiyondaki sayıların ortalamasını hesaplar.

				
					List<Product> products = new List<Product>
        {
            new Product { Name = "Laptop", Price = 1500, StockQuantity = 5 },
            new Product { Name = "Telefon", Price = 450, StockQuantity = 10 },
            new Product { Name = "Mouse", Price = 150, StockQuantity = 7 },
            new Product { Name = "Klavye", Price = 90, StockQuantity = 3 }
        };

        
        int totalProductCount = products.Count();
        // Toplam ürün sayısı


        decimal totalPrice = products.Sum(p => p.Price);
// Toplam fiyat


        decimal averagePrice = products.Average(p => p.Price);
        // Ortalama fiyat

				
			
2.1.10. Min & Max

Min: Koleksiyondaki en küçük öğeyi döndürür.

Max: Koleksiyondaki en büyük öğeyi döndürür.

				
					var numbers = new List<int> { 1, 2, 3, 4 }; 
var min = numbers.Min(); // En küçük sayıyı döndürür 
// Çıktı: 
// min = 1 

var max = numbers.Max(); // En büyük sayıyı döndürür 
// Çıktı: 
// max = 4

				
			
2.1.11. Skip & Take

Skip: İlk n öğeyi atlar.

Take: İlk n öğeyi alır.

Not:Paging işlemlerinde sıklıkla kullanılmaktadır.

				
					int pageNumber = 2;
int pageSize = 10;

var pageData = data
    .Skip((pageNumber - 1) * pageSize)
    .Take(pageSize)
    .ToList();
//2. sayfadan 10 eleman alır.

				
			
2.1.12. Union & Concat

Union: İki koleksiyonu birleştirir, ortak öğeleri bir kez ekler.

Concat: İki koleksiyonu birleştirir, tüm öğeleri ekler.

				
					        // Liste A: Elektronik ürünler
        List<Product> electronics = new List<Product>
        {
            new Product { Name = "Telefon", Category = "Elektronik" },
            new Product { Name = "Klavye", Category = "Elektronik" },
            new Product { Name = "Mouse", Category = "Elektronik" }
        };

        // Liste B: Bilgisayar ürünleri
        List<Product> computers = new List<Product>
        {
            new Product { Name = "Laptop", Category = "Bilgisayar" },
            new Product { Name = "Mouse", Category = "Elektronik" },  // Aynı ürün, ama farklı kategoride
            new Product { Name = "Monitör", Category = "Bilgisayar" }
        };

        var uniqueProducts = electronics.Union(computers).ToList();
        // Union kullanımı (Benzersiz ürünleri birleştirme)

        var allProducts = electronics.Concat(computers).ToList();
        // Concat kullanımı (Tekrar eden ürünler dahil, sırasıyla birleştirme)

				
			
2.1.13. Exept

Bir koleksiyondan başka bir koleksiyonun öğelerini çıkarır.

				
					        // Liste A: Elektronik ürünler
        List<Product> electronics = new List<Product>
        {
            new Product { Name = "Telefon", Category = "Elektronik" },
            new Product { Name = "Klavye", Category = "Elektronik" },
            new Product { Name = "Mouse", Category = "Elektronik" }
        };

        // Liste B: Bilgisayar ürünleri
        List<Product> computers = new List<Product>
        {
            new Product { Name = "Laptop", Category = "Bilgisayar" },
            new Product { Name = "Mouse", Category = "Elektronik" },  // Aynı ürün, ama farklı kategoride
            new Product { Name = "Monitör", Category = "Bilgisayar" }
        };

        
        var uniqueElectronics = electronics.Except(computers).ToList();
// Liste A'da olup Liste B'de olmayan ürünler

				
			
2.1.14. Aggregate

Bir koleksiyondaki öğeleri, belirtilen bir işlemle birleştirir.

				
					        List<Product> products = new List<Product>
        {
            new Product { Name = "Laptop", Price = 1500 },
            new Product { Name = "Telefon", Price = 450 },
            new Product { Name = "Mouse", Price = 150 },
            new Product { Name = "Klavye", Price = 90 }
        };

        decimal totalPrice = products.Aggregate((total, p) => total + p.Price);
// Aggregate kullanarak tüm fiyatları toplama


//Aşağıda verilen örnekte messages dizisindeki Message alanlarını boşlukla birleştirip tek bir satırda ekrana yazdırıyor.
var messages = new[]
{
    new { Id = 1, Message = "Hello" },
    new { Id = 2, Message = "World" },
    new { Id = 3, Message = "LINQ" }
};

string concatenatedString = messages
    .Select(obj => obj.Message)
    .Aggregate((current, next) => current + " " + next);

Console.WriteLine("Concatenated String: " + concatenatedString);

// Çıktı: Concatenated String: Hello World LINQ

				
			
2.1.15. Intersect

İki koleksiyon arasındaki ortak öğeleri bulmak için kullanılır. Yani, her iki koleksiyonda da bulunan benzersiz öğeleri döndürür.

				
					// Liste A: Elektronik ürünler
        List<Product> electronics = new List<Product>
        {
            new Product { Name = "Telefon", Category = "Elektronik" },
            new Product { Name = "Klavye", Category = "Elektronik" },
            new Product { Name = "Mouse", Category = "Elektronik" }
        };

        // Liste B: Bilgisayar ürünleri
        List<Product> computers = new List<Product>
        {
            new Product { Name = "Laptop", Category = "Bilgisayar" },
            new Product { Name = "Mouse", Category = "Elektronik" },  // Ortak ürün
            new Product { Name = "Monitör", Category = "Bilgisayar" }
        };

        var commonProducts = electronics.Intersect(computers, new ProductComparer()).ToList();
        // Intersect kullanarak her iki listede bulunan ortak ürünler

				
			

LINQ ile Performansı Üst Seviyeye Taşıyın

LINQ, doğru kullanıldığında yalnızca kodunuzu sadeleştirmekle kalmaz, aynı zamanda veri işlemlerinde ciddi performans artışları da sağlar. Bu makalede incelediğimiz gelişmiş kullanım teknikleri, gerçek dünya uygulamalarında daha hızlı, verimli ve ölçeklenebilir projeler oluşturmanız için güçlü bir temel sunuyor.

Performans optimizasyonundan veri modellemesine kadar uzanan bu detaylar, özellikle büyük veri setleriyle çalışan uygulamalarda LINQ’ün potansiyelini tam anlamıyla ortaya çıkarmanıza yardımcı olur.

Unutmayın: Küçük hatalar büyük performans kayıplarına yol açabilir. LINQ’ü etkili kullanmak, sadece doğru sorgular yazmaktan değil, aynı zamanda her adımda doğru stratejiler uygulamaktan geçer.

🚀 Verimix ile Bilginizi Güçlendirin, Teknolojinizi İleri Taşıyın!

LINQ ve daha birçok ileri seviye yazılım teknolojisi hakkında derinlemesine bilgi edinmek için blog sayfamızdaki diğer yazılarımızı keşfedin.

Verimix Yazılım olarak, iş süreçlerinizi hızlandıran, performansı artıran ve rekabet gücünüzü destekleyen yenilikçi çözümler geliştiriyoruz.

Daha fazlasını öğrenmek ve dijital dönüşüm yolculuğunuzda Verimix ile tanışmak için hakkımızda sayfamızı ziyaret edin!

Facebook
Twitter
LinkedIn