LINQPad yazılımı, SqlServer, Oracle, OData servisleri gibi veri kaynakları üzerinde LINQ sorgularını kullanarak sorgular çalıştırabilen ve C#, VB, F# gibi programlama dillerini destekleyen bir editördür.
LINQPad ile desteklenen diller ve gerçekleştirilebilecek operasyonlar seçenekler halinde geliştiricilere sunulmuştur.
C# Expression
C# Statements
C# Program
VB Expression
VB Statements
VB Program
SQL
ESQL
F#Expression
F# Program
Geliştiriciler olarak hızlı bir şekilde denemeler yapmak istediğimiz durumlar olabilir. Bu durumda hemen Visual Studio arayüzünde bir proje oluşturarak ya da mevcut bir proje üzerinde merak ettiğimiz kodları çalıştırmak durumunda kalırız. Ancak LINQPad ile hızlı bir şekilde istediğimiz sonucu hemen görebiliriz.
Bu yazıda System.Linq kütüphanesinden faydalanarak rastgele şifre üretmenin ne kadar pratik ve basit olduğunu inceleyeceğiz. Bu pratik çözüme burada rastladım ve herkese faydalı olacağını tahmin ederek paylaşmak istedim.
var chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
var random = new Random();
var result = new string(
Enumerable.Repeat(chars, 8)
.Select(s => s[random.Next(s.Length)])
.ToArray());
Enumerable.Repeat fonksiyonunun syntax düzeni şu şekildedir:
public static IEnumerable<TResult> Repeat<TResult>(
TResult element,
int count
)
Çalışma şekli ise TResult türünde Count kadar tekrar eden bir yığın üretecek şekilde ayarlanmıştır. Örneğin 15 tane “Okul” sözcüğü üret şeklide çalışır.
Yukarıdaki şifre üretmek için oluşturulan örnekte bizim verdiğimiz bir diziden her defasında rastgele bir karakter çekildiği için tekrarlı veri yığını oluşmuyor. Sonuç olarak count değeri kadar karakter içeren bir şifre oluşturabiliyoruz.
Programlama dünyasında nesneler arası aktarım yapılması amacıyla geliştirilmiş olan Automapper kütüphanesi üzerinde yaptığım performans sonuçlarını yazmak istedim.
C# kodu ile geliştirdiğim örnek uygulama üzerinde sırsıyla 10, 100, 1000, 10000 ve 100000 kayıt üzerinde üç farklı şekilde Mapping işlemi yapmayı denedim.
Örnek senaryoda Product adında bir sınıf düşünün. Bu sınıfın 10 farklı property üyesi olsun. Ben bu 10 üyeli Product tipini taşımak istemediğimden ProductSummary adında 2 üyesi olan bir sınıf oluşturuyorum.
public class Product
{
public int id { get; set; }
public string Name { get; set; }
public string Color { get; set; }
public string Model { get; set; }
public string Size { get; set; }
...
..
.
}
public class ProductSummary
{
public int id { get; set; }
public string Name { get; set; }
}
Doğal olarak Product nesnesini bir şekilde ProductSummary nesnesine aktarmalıyım. Bu işlemi Automapper kütüphanesi ile ve manuel olarak denediğimde ve süreleri milisaniye cinsinden ölçtüğümde ilginç rakamlarla karşılaştım.
List<Product> products = new List<Product>();
Kayıt sayısı sırayla 10, 100, 1000, 10000 ve 100000 olarak değiştiriliyor ve her seferinde Mapping işlemi deneniyor.
Mapping-1 (Yöntem-1 Foreach döngüsüyle tek tek Mapping işlemi)
10 kayıt için süre 121 milisecond
100 kayıt için süre 127 milisecond
1000 kayıt için süre 155 milisecond
10000 kayıt için süre 498 milisecond
100000 kayıt için süre 5298 milisecond
10 kayıt için süre 133 milisecond
100 kayıt için süre 126 milisecond
1000 kayıt için süre 221 milisecond
10000 kayıt için süre 152 milisecond
100000 kayıt için süre 339 milisecond
Mapping-3 (Yöntem-3 Automapper kullanmadan manuel olarak nesneleri oluşturmak)
foreach (var product in products)
{
ProductSummary summary = new ProductSummary();
summary.id = product.Id;
summary.Name = product.Name;
}
10 kayıt için süre 1 milisecond
100 kayıt için süre 1 milisecond
1000 kayıt için süre 2 milisecond
10000 kayıt için süre 4 milisecond
100000 kayıt için süre 42 milisecond
var data = products.Select(summary=>
new ProductSummary{
Id= summary.Id,
Name = summary.Name
});
10 kayıt için süre 1 milisecond
100 kayıt için süre 1 milisecond
1000 kayıt için süre 1 milisecond
10000 kayıt için süre 1 milisecond
100000 kayıt için süre 1 milisecond
Mapping Raporları
Bu sonuçlara göre Automapper kütüphanesi Mapping işlemlerinde biraz yavaş kaldığı aşikardır. En hızlı yöntemin LINQ Extension metodları yardımıyla Mapping işleminin olduğu ortaya çıkmaktadır. 100.000 kaydın mapping işlemine tabi tutulması 1 milisaniye sürmektedir. Aynı işlem Automapper kütüphanesi ile 5000 milisaniyeden fazla sürmektedir. Yani zaman probleminin olmadığı uygulamalarda Automapper kullanılabilir. Ancak işlemleri uzun sürede bitirmesi amacıyla yazılmış bir uygulama şu ana kadar hiç görmedim.
LINQ sorguları kolleksiyon temelli yapılarda sorgulamalar ve seçimler yapmak için bize imkan sağlar. Döngülerle diziler içerisinde boğuşmadan istediğimiz formatta sonuç almamıza yardımcı olurlar.
Bazen ihtiyaçlarımız doğrultusunda bir tipte oluşturulmuş kolleksiyon içerisinden başka bir tipte seçimler yapmak durumunda kalabiliriz. Bu noktada kurtarıcı olarak yine LINQ sorgularından faydalanabilmekteyiz.
Örneğin bir ürüne ait bilgileri tutan “Product” tipine ait kolleksiyon içerisinden bize lazım olan ürün başlıklarını seçip alacağımız “ProductTitle” tipli kolleksiyon oluşturma gereği duyduğumuz bir senaryo düşünebiliriz. Bu durumda tüm “Product” nesnesini taşımak yerine ürün adlarını barındıran “ProductTitle” adlı tipi tercih etmiş oluyoruz. Bu şekildeki bir seçimi yapmak için şu şekilde bir LINQ sorgusu yazabiliriz.
var productTitles = db.Products.Select(p => new ProductTitle{
Id = p.Id,
Name = p.Name
});
Ancak bazı durumlarda seçim yaptığımız tip özellikleri, Property ataması ile değil de bir kurucu metod (Constructor) ile tipe enjekte edileceği durumu senaryo edecek olursak nasıl bir durumla karşılaşacağımıza bakalım.
StoreEntities db = new StoreEntities();
var productTitles = db.Products.Select(p => new ProductTitle(p));
Yukarıdaki sorguyu, eğer bir Entity Framework modeli üzerinde çalıştıracak olursak karşımıza şu şekilde bir hata mesajı çıkacaktır.
Unhandled Exception: System.NotSupportedException: Only parameterless constructors and initializers are supported in LINQ to Entities.
LINQ provider, ProductTitles tipinini kurucu metodunda nasıl bir kodun çalıştırılacağından habersizdir. Entity Framework ise LINQ sorgularını olduğu gibi T-SQL sorgularına dönüştürmeye çalışır. Fakat sorgu içerisindeki bir tipin(ProductTitle) kurucu metodunda neler olup bittiğini bilmediğinden işlem durdurulur ve hata raporu oluşturulur.
Bu durumun çözüm yolu ise Entity Framework tarafından IQueryable olarak sunulan kolleksiyonu AsEnumerable extension metodu yardımıyla IEnumerable olarak değiştirmektir.
StoreEntities db = new StoreEntities();
var productTitles = db.Products
.AsEnumerable()
.Select(p => new ProductTitle(p));
Burada sorguda AsEnumerable() extension metodu önce veriyi çekiyor. Ardından seçilen kolleksiyon içerisinden seçim işlemi yapılıyor. Bu sayede hata giderilmiş oluyor. Entity Framework sorgularının IQueryable ve IEnumerable karşısındaki davranışları ve T-SQL dönüşümünü incelemek için Burak Selim Şenyurt’un buradaki ipucundan faydalanabilirsiniz.
Bu yazımızda da LINQ sorgularının lambda ifadeleriyla nasıl yazıldığını inceleyelim. Uzun uzun yazılan LINQ sorgularını tek satırda yazmak mümkündür. Bu sayede hem temiz hemde rahat okunabilir bir kod ortayaçıkıyor.
Bir Employee sınıfı oluşturup, sorgulama yapmak için de bu tipe ait bir liste oluşturarak işe başlayabiliriz.
public class Employee
{
public int id { get; set; }
public string Name { get; set; }
public double Salary { get; set; }
public override string ToString()
{
return string.Format("Name: {0} Salary: {1}",Name, Salary);
}
}
Employee tipine ait liste de şu şekilde olsun.
List<Employee> Employees = new List<Employee>
{
new Employee{ id=1102, Salary=1250, Name="Jim" },
new Employee{ id=1802, Salary=2250, Name="Tim" },
new Employee{ id=1650, Salary=3250, Name="Kim" },
new Employee{ id=2102, Salary=1750, Name="Sim" },
new Employee{ id=3182, Salary=1350, Name="Him" },
};
Sorgu: Maaşı 1900’den küçük olan çalışanları ada göre sıralayarak göster.
Linq Sorgusu
var linqResult = from c in Employees
where c.Salary < 1900
orderby c.Name
select c;
Lambda Expression Sorgusu
var lambdaResult = Employees.Where(i => i.Salary < 1900).OrderBy(i => i.Name);
Sorguları çeşitlendirmek mümkündür. Sonuçta bu örnek göldeki bir damla gibidir.