LINQPad Programcıların Oyun Alanı

25 Haz

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

Adsız

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.

Örneğin C# LINQ ile rasgele şifre üretmek için hemen bir deneme yapmak istersek:

Adsız

Yazmak istediğimiz ifadeleri tamamladıktan sonra sonucu görmek için sadece .Dump() extension metodunu çalıştırmak yeterlidir.

Harici kütüphaneleri ve Nuget paketlerini referans olarak LINQPad’e eklemek ve çalıştırabilmek mümkündür.

 

C# LINQ ile Rastgele Şifre Üretmek

4 Nis

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());

Olayın gelişimini incelediğimizde Enumerable sınıfının Repeat fonksiyonundan faydalanıldığını görüyoruz.

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.

Mapping İşlemleri ve Automapper Performans Testleri

10 May

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)

foreach (var product in products)
{
    ProductSummary summary = Mapper.Map<Product, ProductSummary>(product);
}

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

Mapping-2 (Yöntem-2 Kolleksiyonu direk mapping işlemine sokmak)

IEnumerable<ProductSummary> summary = Mapper.Map<IEnumerable<Product>,
                                    IEnumerable<ProductSummary>>(products);

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

Mapping-4 (Yöntem-4 LINQ Extension metodlar yarımıyla mapping işleminin gerçekleştirilmesi)

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ı
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.

Bir sonraki yazıda görüşmek dileğiyle.

LINQ sorgularında Karşılaşılan NotSuportedException

11 Mar

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.

Bir sonraki yazıda görüşmek dileğiyle.

LINQ / Lambda Expression

16 Tem

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.