Dynamic Expression API nam-ı diğer Dynamic LINQ

Yazar: Mehmet Sencer KARADAYI
Kategori: C#.NET & VB.NET
Eklenme Tarihi: 10.2.2010 22:08:42



LINQ, piyasaya çıktığı günden beri çok konuşulan bir olgu. Yazma zamanlı, c# ya da vb syntax'ini kullanarak sql sorguları oluşturmak insanların çok hoşuna gitti. Peki, sorgularımızı "dinamik" oluşturmak istersek ne yapacağız?

LINQ(Language Integrated Query) .NET 3.5 ve Visual Studio 2008 ile hayatımıza girdi. C# ile kod yazarken SQL'de sorgu yazıyor gibi sorgu yazmak bir çok kişinin hoşuna gitti. "LINQ hoş ama daha dinamik sorgu yazabilsek ..." dediğimiz zamanda imdadadımıza Dynamic Expression API(DynamicLINQ) yetişti ve bize string tabanlı sorgu yazma imkanı, başka bir açıdan, kolaylığı sundu.Bu makalemde DynamicLINQ nedir?, nasıl kullanılır? ve biz yazılımcıları DynamicLINQ kullanmaya itebilecek senaryoları soruları üzerine konuşuyor olacağız.

Not : Sınıfın asıl adı Dynamic Expression fakat ben sınıftan makale boyunca DynamicLINQ olarak bahsedeceğim.

undefined

DynamicLINQ nedir?

LINQ'da sorgu çekerken ya syntax içindeki operatörleri ya da Lambda extension metodlarını kullanırız değil mi? İşte DynamicLINQ'da işler biraz değişiyor :

[C#] Klasik LINQ

undefined

               DBDataContext DB = new DBDataContext();

               var kayit = from a in DB.Kisis where a.Ad == "Mehmet" select a;

               Console.WriteLine(kayit.FirstOrDefault().Soyad);

undefined

[C#] Dynamic LINQ

undefined

               DBDataContext DB = new DBDataContext();

               var kayit = DB.Kisis.Where("Ad==@0", "Mehmet");

               Console.WriteLine(kayit.FirstOrDefault().Soyad);

undefined

Gördüğünüz gibi Dynamic LINQ da "Where" koşulunu "String" bir değer olarak verdik. Her iki sorguyu da SQL Profiler ile takip ettiğimiz zaman SQL'e aslında aynı sorgunun gittiğini göreceğiz yani geri dönen değerlerde de hiçbir farklılık olmayacaktır.

Yukarıdaki basit sorgu örneğini de göz önüne alırsak, kısaca DynamicLINQ'yu sorguların String tabanlı yapıldığı genişletme(extension) foksiyonları içeren bir kütüphane olarak tanımlayabilirz.

Nasıl Kullanılır?

Daha önce de belirttiğim gibi DynamicLINQ aslında genişletme(extension) metodları içeren bir kütüphane.

[DATACONTEXTDeğişkeni].[TABLOADI]. dediğimiz zaman System.LINQ Namespace'i ile birikte gelmeyen, ek metodlar gözümüze çarpıcaktır.Bu metodlar aşağıda belirttiğim gibidir :

public static IQueryable Where(this IQueryable source,  string predicate, params object[] values);
public static IQueryable<T> Where<T>(this IQueryable<T> source,   string predicate, params object[] values);
public static IQueryable Select(this IQueryable source,    string selector, params object[] values);
public static IQueryable OrderBy(this IQueryable source,    string ordering, params object[] values);
public static IQueryable<T> OrderBy<T>(this IQueryable<T> source,  string ordering, params object[] values);
public static IQueryable Take(this IQueryable source, int count);
public static IQueryable Skip(this IQueryable source, int count);

Dynamic Expression API'ın içerdiği extension metodların listesi

Gördüğünüz üzere metodlar, string değerler ve object dizileri alan metodlar.

İşte DynamicLINQ'nun altında yatan felsefe de bu : yazma zamanlı değil çalışma zamanlı sorgular oluşturmak.Bu sayede sorgulayacağımız kıstasların değişkenliğini tolere etmiş oluyoruz.

Lafı fazla dolandırmadan metod kullanımlarıyla ilgili örneklere geçelim isterseniz.

-> WHERE Koşulunun Kullanımı

                var kayit = DB.Kisis.Where("Ad==@0", "Mehmet");        

                Console.WriteLine(kayit.FirstOrDefault().Soyad);

undefined

Yukardaki kod parçasında "Kisi" tablosunun "Ad" kolonundaki değeri "Mehmet" olan kayıt veya kayıtlardan ilkinin "Soyadını" ekrana yazdırdık.

Sorgularda parametre tanımlama tarzı aslında aşikar olduğumuz bir tarz :

    "Ad==@0"

 

undefined
undefined

Parametreler @0,@1 gibi yani aynı SQL'deki gibi tanımlanıyor.

 

    , "Mehmet"

undefined

 

      YA DA

 

    , new object[]{"Mehmet"}

undefined

 

Parametre değerleri ise ya virgülden sonra direk veriliyor ya da bir obje listesi olarak atanıyor.Aslında aralarında hiç bir fark yok.

 

 

-> OrderBy Kullanımı

 

                var kayit = DB.Kisis.OrderBy("ID");

                foreach(Kisi per in kayit)

                {

                    Console.WriteLine("ID : {0} - Ad : {1} - Soyad : {2} ", per.ID,per.Ad, per.Soyad);

                }

undefined

 

Yukarıda da gördüğünüz gibi DynamicLINQ da herşey String tabanlı. Çok da zor değil değil mi? Hangi kolona göre sıralama yapmak istiyorsak onu OrderBy metoduna string olarak veriyoruz ve iş bitiyor.

 

-> Select Kullanımı

 

                var kayit = DB.Kisis.Select("new(Ad,Tip)");

                foreach (var per in kayit)

                {

                    Console.WriteLine(per.ToString());

                }

undefined

"Select" kullanımı da gayet basit : "new(kolon1,kolon2)" tarzında istediğiniz kolonu çekebiliyorsunuz. Hatta şöyle de kullanabiliriz :

                var kayit = DB.Kisis.Select("new(Ad as AdSoyad,Tip)");

                foreach (var per in kayit)

                {

                    Console.WriteLine(per.ToString());

                }

undefined

 

Yukardaki kodu derlediğimiz zaman çıkan sonuç

Gördüğünüz gibi as deyimi ile yeni oluşturduğumuz dinamik sınıfımızın alan etiketlerini de değiştirebiliyoruz.

-> GroupBy Kullanımı

    var kayit = DB.Kisis.GroupBy("Tip","new(Tip)");

undefined

GroupBy kullanımı ise yukarıdaki örnekteki gibidir.Gruplama yapılacak kolon adı ilk değişkene, gruplama sırasında oluşturulacak dinamik sınıfın alan adını da ikinci değişkene atıyoruz.Bu sayede tablodak kayıtları bir ağaç haline getirmişiz gibi düşünülebilir.

Herşey görüldüğü üzere süper, herşey dinamik. Peki, yazdığımız sorgu yanlış ise ne olucak?

Linq da yazdığımız sorgu hatalı ise hatanın hemen farkına varırız; çünkü, yaptığımız aslında syntax hatasıdır ve yorumlayıcı bunun hemen farkına varır.

DynamicLINQ da ise sorgu olarak gönderdiğimiz string değerin içinde bir hata olup olmadığı ancak çalışma zamanında belli olur.Bu yüzden DynamicLINQ ile birlikte yeni bir hata sınıfı geliyor : ParseException

Hemen nasıl kullanıldığına bir göz atalım.

                try

                {

                    var kayit = DB.Kisis.Select("new(Ad AdSoyad,Tip)");

                    foreach (var per in kayit)

                    {

                        Console.WriteLine(per.ToString());

                    }

                }

                catch(ParseException ex)

                {

                    Console.WriteLine("Pozisyon : {0} \nHata : {1} ", ex.Position ,ex.Message);

                }

undefined

Ad ve AdSoyad arasındaki as ifadesini sildim farkettiyseniz ve işte sonuç :

Hata çıktısı


->Take ve Skip ifadelerinin kullanımı

Take(int count) ve Skip(int count) metodları zaten tanıdığımız metodlar ama ben bir örnek vermek istiyorum.

            try

            {

                var kayit = DB.Kisis.Where("Tip=@0", new object[] { 'A' });

                Console.WriteLine(kayit.Skip(1).Take(1).FirstOrDefault().Ad);

            }

            catch (ParseException ex)

            {

                Console.WriteLine("Pozisyon : {0} {2}Hata : {1} ", ex.Position, ex.Message, "\n");

            }

undefined

Yaptığımız işlem, geri dönen kayıtlar arasında ilkini atlayıp sonrakiler arasından ilkini seçmek sonra da o kayıdın Ad değerini göstermek.Take ve Skip metodlarında bir sıkıntınız olacağını düşünmüyorum bu yüzden kısaca geçtim.

Neden DynamicLINQ kullanalım ki?

Hala kafasında bu konu hakkında soru işareti olanlarımız varsa başımdan geçen bir olayı anlatmak isterim.

Bir form ekranı hayal edin öyle ki üzerinde bir datagrid üç combobox ve bir de datetimepicker olsun.

Comboboxlardan ve DatePickerdan gelen verilerle filtreleme işlemi yapıp (filtreleme işleminde tüm kombinasyonlar olacak örn:2 combobox + datepicker dan gelen veriye göre filtreleme...) bunu gride yansıtmanız istense LINQ Expressionları kullanarak nasıl yaparsınız?

Bu senaryoda aklıma yirmi dört adet fonksiyon yazmaktan başka bir fikir gelmiyor.

İşte tam bu sırada DynamicLINQ yardımıma yetişti ve aşağıdaki kod ortaya çıktı :

                   if (cmbMusteri.SelectedItem.Value != "")

                   {

                       CID = DataReader.GetInt32(cmbMusteri.SelectedItem.Value);

                      if(str!=0)

                      {

                          Sort += " && ";

                      }

                      Sort += string.Format(" CustomerID={0} ", CID);

                      str += 1;

   

                   }

                   if (cmbHizmet.SelectedItem.Value != "")

                   {

                       HID = DataReader.GetInt32(cmbHizmet.SelectedItem.Value);

                       if (str != 0)

                       {

                           Sort += " && ";

                       }

                       Sort += string.Format(" workID={0} ", HID);

                       str += 1;

                   }

   

                   if (DataReader.GetDateTime(dtTarih.Value) != DateTime.Parse("01.01.0001"))

                   {

                       tarih = DataReader.GetDateTime(dtTarih.Value);

                       if (str != 0)

                       {

                           Sort += " && ";

                       }

                       Sort += string.Format(" date=@1 ");

                       str += 1;

                   }

   

                   if(cmbStatus.SelectedItem.Value!="")

                   {

                       SID = DataReader.GetInt32(cmbStatus.SelectedItem.Value);

                       if (str != 0)

                       {

                           Sort += " && ";

                       }

                       Sort += string.Format(" state_of={0} ", SID);

                       str += 1;

                   }

undefined

Not : DataReader. lara çok takılmayın o fonksiyonlar sadece Convert.To'lar :)

Bu işlemler sonucu oluşan string değişkeni, yani yukarıdaki örnekde SORT, verin bir metoda gerisini DynamicLINQ halleder.

Böylece DynamicLINQ'nun ana hatlarının üstünden geçtik.Daha derine inmek isteyen arkadaşlar olursa makalenin ekindeki projelerin içinde System.Linq.Dynamic projesini inceleyebilirler.Bu proje kütüphanenin açık kaynak kodunu içerir.

İsteyenler linkten Microsoft'un yayınladığı örnekleri indirip inceleyebilirler.

Sona sakladığım çok güzel bir dipnot: Sorgulama için oluşturduğunuz string değeri ister C# ister VB.NET syntax'ı kullanarak yazabilirsiniz.

[C#]

    var kayit = DB.Kisis.Where("Ad==@0 && Soyad==@1", new object[] { "Mehmet","Karadayı" });

undefined

[VB.NET]

    Dim kayit = DB.Kisis.Where("Ad=@0 and Soyad=@1", New Object() { "Mehmet","Karadayı" });

undefined

Bu makalemizin sonuna geldik. Başka bir makalede görüşmek üzer herkese iyi kodlamalar diliyorum.

 


Mehmet Sencer KARADAYI

2008 'den beri MCPD, MCTS ünvanlarını taşıyan yazar, Orta Doğu Teknik Üniversitesi 'nde Bilgisayar Mühendisliği bölümünde eğitimine devam etmektedir.
Bu makaleye ilk yorum yapan siz olun.

Yorumunuz