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 :
undefined
Parametreler @0,@1 gibi yani aynı SQL'deki
gibi tanımlanıyor.
undefined
YA DA
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.