SİTE
İÇİ ARAMA |
|
|
Blogroll |
|
|
|
|
|
|
LINQ : Daha Fazla Sorgu |
|
| Gönderiliyor lütfen bekleyin... |
|
|
Bu günlerde hepimiz .Net Framework 3.0
ve getirileri üzerine yoğunlaşmış durumdayız. Özellikle mimari anlamda
yapılan köklü değişimler söz konusu. Bu köklü değişiklikler; Windows
uygulamalarının yeni yüzü olan WPF (Windows Presentation Foundation) ve
XAML (eXtensible Application Markup Language), dağıtık mimariyi tek çatı
altında toplamayı başaran WCF (Windows Communication Foundation), akış
şemaları ve iş süreçlerinin .Net plaformuna dahil edilmesini sağlayan
WF(Workflow Foundation) ve CardSpace olarak sıralanabilir. Ancak
bunların dışında Microsoft’
un gelecek vizyonu içerisinde yer alan en önemli konulardan biriside C#
3.0 konusudur. Bildiğiniz gibi C#, sıfırdan geliştirilmiş ve atası olan
nesne yönelimli dillerin en iyi özelliklerini bünyesinde birleştirerek
bunu güçlü bir Framework üzerinde kullanabilmemizi sağlayan bir dildir.
Zaman içerisinde C# 2.0 ile gelen yenilikler şu anda tüm C#
geliştiricilerin hayatının bir parçası haline gelmiştir. Şimdi herkesin
gözü C# 3.0 üzerinde.
C# 3.0, beraberinde LINQ (Language Integrated Query),
DLINQ
(Database Language Integrated Query) ve
XLINQ
(Xml Language Integrated Query) gibi yeni teknolojileride getirmekte ve
desteklemektedir. Biz bu makalemizde daha fazla LINQ ifadesi yazmaya
çalışacağız. Onbir basit LINQ ifadesi ile dil tabanlı sorguları daha
yakından tanımaya başlıyacak ve elimizdeki gücün farkına varacağız.
Bildiğiniz gibi LINQ (Language Integrated Query) özellikle dil içerisinde, Sql tarzı sorgular
yazabilmemizi ve bunları var olan IEnumerable<T> türevli tipler
üzerinde kullanabilmemizi sağlamaktadır. Ancak özellikle LINQ içerisinde
kullanılabilen operatörler göz önüne alındığında, oldukça etkili
sonuçlar alabileceğimiz ortadır. Temel olarak LINQ içerisindeki
operatörler aşağıdaki başlıklar altında toplanmıştır. (Elbetteki bu
bilgiler hala deneme aşamasında olan bir sürece aittir ve değişebilir.)
- Kısıtlama Operatörleri
(Restriction Operators) -> Where
- Gruplama Operatörleri (Grouping
Operators) -> Group
- Sıralama Operatörleri (Ordering
Operators) -> OrderBy, ThenBy, Reverse
- Bölümleme Operatörleri
(Partitioning Operators) -> Take, Skip, TakeWhile, SkipWhile
- Seçme Operatörleri (Projection
Operators) -> Select
- Set Operatörleri (Set Operators)
-> Distinct, Union, Intersect, Except
- Dönüştürme Operatörleri
(Conversion Operators) -> ToArray, ToList, ToDictionary, OfType
- Eleman Operatörleri (Element
Operators) -> First, FirstOrDefault, ElementAt
- Üretim Operatörleri (Generation
Operators) -> Range, Repeat
- Gruplama Fonksiyonu Operatörleri
(Aggregate Operators) -> Count, Sum, Min, Max, Averaga, Fold
- Ölçüm Operatörleri (Quantifiers
Operators) -> Any, All
- Çeşitli Operatöler (Miscellaneous
Operators) -> Concat, EqualAll
- Özel Seri Operatörleri (Custom
Sequence Operators) -> Combine
Şimdi gelin bu operatörlerin bir
kısmını incelemeye çalışalım. Öncesinde program ortamında ele
alabileceğimiz bazı veri kümelerine ihtiyacımız olacak. Bu veri
kümeleri tamamıyla test amaçlı olacaktır. Bunun için
AdventureWorks veritabanında yer alan Product ve ProductSubCategory
tablolarından faydalanabiliriz. Amacımız ilk olarak buradaki
tablolardan test amacıyla kullanabileceğimiz veri kümelerini program
ortamı içerisinde yer alan generic koleksiyonlara aktarmaktır. LINQ konusu söz
konusu olduğu içinde, C# 3.0 dili özelliklerinden de faydalanmaya
çalışacağız.
 |
Var olan Visual Studio 2005
sürümünde LINQ projeleri yazmak ve test edebilmek için
LINQ Preview proje şablonunu kullanamız gerekmektedir.
Özellikle C# 3.0 yenilikleri ile ilişkili olarak
Sefer Algan’ ın konu ile ilgili makalesinden
faydalanabilirsiniz. |
Yardımcı sınıfımızın kodları
aşağıdaki gibidir.
Product Sınıfı;
public
class Product
{
public int ProductId;
public string Name;
public double ListPrice;
public DateTime SellStartDate;
public DateTime SellEndDate;
public int ProductSubCategoryId;
public override string ToString()
{
return ProductId.ToString() + " " +
Name + " " + ListPrice.ToString("C2") + " " +
SellStartDate.ToString() + " " + SellEndDate.ToString() + "
" + ProductSubCategoryId.ToString();
}
} |
ProductSubCategory Sınıfı;
public
class ProductSubCategory
{
public int ProductSubCategoryId;
public string Name;
public override string ToString()
{
return
ProductSubCategoryId.ToString() + " " + Name;
}
} |
Product ve ProductSubCategory
sınıflarımızda dikkat ederseniz özellik (Property) kullanmadık.
Ayrıca içerideki elemanlara ilk değerlerini kolayca atayabilmek için
yapıcı metod (constructor) da yazmadık. Burada C# 3.0 ile gelen
nesne başlatıcılarını (object initializers) kullanacağımız
için özellike ve yapıcı metod kullanımını terk ettik. Şimdi bu
tiplerden üyelere yükleme yapacak olan Helper sınıfımızın
kodlarınıda aşağıdaki gibi geliştirelim.
Helper.cs
public
class Helper
{
public static List<Product> UrunleriYukle()
{
List<Product> urunler = new
List<Product>();
using (SqlConnection conn = new
SqlConnection("data
source=localhost;database=AdventureWorks;integrated
security=SSPI"))
{
SqlCommand
cmd = new SqlCommand("SELECT ProductID, Name, ListPrice,
SellStartDate, SellEndDate, ProductSubcategoryID FROM
Production.Product WHERE (Name IS NOT NULL) AND (ListPrice
IS NOT NULL) AND (SellStartDate IS NOT NULL) AND
(SellEndDate IS NOT NULL) AND (ProductSubcategoryID IS NOT
NULL)", conn);
conn.Open();
SqlDataReader
dr=cmd.ExecuteReader();
while
(dr.Read())
{
// Object Initializers kullanarak nesneye ilk değerlerini
atıyoruz.
Product urn=new
Product{ProductId=Convert.ToInt32(dr["ProductID"]),Name=dr["Name"].ToString(),ListPrice=Convert.ToDouble(dr["ListPrice"]),SellStartDate=Convert.ToDateTime(dr["SellStartDate"]),SellEndDate=Convert.ToDateTime(dr["SellEndDate"]),ProductSubCategoryId=Convert.ToInt32(dr["ProductSubCategoryId"])};
urunler.Add(urn);
}
}
return urunler;
}
public static List<ProductSubCategory> AltKategorileriYukle()
{
List<ProductSubCategory>
altKategorileri = new List<ProductSubCategory>();
using (SqlConnection conn = new
SqlConnection("data
source=localhost;database=AdventureWorks;integrated
security=SSPI"))
{
SqlCommand
cmd = new SqlCommand("SELECT ProductSubCategoryId,Name From
Production.ProductSubCategory", conn);
conn.Open();
SqlDataReader
dr=cmd.ExecuteReader();
while
(dr.Read())
{
//
Object Initializers kullanarak nesneye ilk değerlerini
atıyoruz.
ProductSubCategory subCat=new
ProductSubCategory{ProductSubCategoryId=Convert.ToInt32(dr["ProductSubCategoryId"]),Name=dr["Name"].ToString()};
altKategorileri.Add(subCat);
}
}
return altKategorileri;
}
} |
UrunleriYukle ve
AltKategorilerYukle isimli metodlarımız sadece bize yardımcı olacak
üyelerdir. Dikkat ederseniz her ikiside generic List koleksiyonu
tipinden değişkenler döndürmektedirler. Biz bu koleksiyonlar
üzerinde LINQ sorgularımızı denemeye çalışacağız. Testleri daha
kolay yapabilmek için şimdilik bir Console uygulamasından devam
edeceğiz. Dilerseniz ısınma turlarımızda basit Select ve Where
kullanımları ile başlayalım.
Sorgu 1: Ürünlerden belirli bir alt
kategoride olanların bulunması.
var
products = Helper.UrunleriYukle();
var subCategories=Helper.AltKategorileriYukle();
Console.WriteLine("\nProductSubCategoryId’ si 1 olan
Urunler\n");
var resultSet=from
p in products
where p.ProductSubCategoryId==1
select p;
foreach(Product prd in resultSet)
Console.WriteLine(prd.ToString()); |
İlk olarak kaynak verilerimizi
Helper sınıfı içerisine dahil ettiğimiz static metodlarımız
yardımıyla yüklüyoruz. (Buradan sonraki örnek kodlarımızda
products ve subCategories isimli değişkenlerin taşıdığı koleksiyon
verilerini kullanacaktır.) Bu işlemler sırasındada veri tipini kolayca
kullanabilmek için var anahtar sözcüğünden faydalanmaktayız. Sorgu
ifademiz içerisinde select, where ve from anahtar
sözcükleri kullanılmaktadır. İfademize göre products isimli
koleksiyon içerisindeki her bir nesne örneği p adıyla
tanımlanmaktadır. Sonrasında ise bu p adlı nesnelerden
ProductSubCategoryId özelliğinin değeri 1 olanların çekilmesi
sağlanmıştır. Dikkat ederseniz, p nesnesinin işaret ettiği tür
Product tipi olduğu için p.ProductSubCategoryId gibi bir ifade
yazılabilmiştir. Uygulamamızı çalıştırdığımızda aşağıdaki ekran
görüntüsüne benzer bir sonuç alırız.
Şimdi elimizde LINQ gibi bir seçenek
olmadığını düşünelim. Bu durumda yukarıdaki ihtiyacı karşılamak için
aşağıdakine benzer bir kod parçası yazabilirdik. Önce, generic
koleksiyon içerisinde dolaşır, her bir Product nesnesinin
ProductSubCategoryId değerine bakar ve 1 olanları, başka bir generic
List koleksiyonu içerisinde toplardık.
List<Product> urunler = new List<Product>();
foreach (Product prd in products)
if (prd.ProductSubCategoryId == 1)
urunler.Add(prd); |
Lakin daha karmaşık sorgulama
ifadeleri göz önüne alındığında durum dahada zorlaşabilir. İmkansız
değildir ama daha fazla kod yazmamızı, efor sarfetmemizi ve zaman
zaman optimizasyonu zor olacak kodlar üretmemize neden olacak
durumlarla karşılaşabiliriz.
Örneğin, Alt Kategorilerin ve Urunlerin birbirleriyle
birleştirileceğini, birleştirilen küme üzerinde gruplama
yapılacağını ve hatta bu gruplamalara göre toplam fiyat, toplam ürün
sayısı gibi değerlerin elde edileceğini düşünebiliriz. (Bu pek
çok Sql programcısına tanıdık gelecek bir ihtiyaçtır.) Bu tarz
bir ihtiyacı karşılayacak kod parçasını elbetteki yazabiliriz. Ama
LINQ ile bunu ve benzerlerini çok daha basit bir biçimde, tek
satırlık ifadelerde gerçekleştirme şansına sahibiz. Dilerseniz yeni
örnekler ile alıştırmalarımıza devam edelim.
Sorgu 2: Liste fiyatı 3000 birimin
üzerinde olan ürünleri isimlerine göre tersten sıralı olacak şekilde
elde etmek.
var
resultSet2=from
p in products
where p.ListPrice>=3000
orderby p.Name descending
select p;
Console.WriteLine("\nFiyatı 3000’ den büyük olan Urunler.
Name alanına göre tersten sıralı. \n");
foreach(Product prd in resultSet2)
Console.WriteLine(prd.ToString()); |
Dikkat ederseniz Liste fiyatına
göre kontrol işlemini gerçekleştirmek için yine where operatöründen
faydalanıyoruz. Sıralamayı Product tipindenki Name alanına göre
tersten sıralatmak istediğimiz içinde, orderby ve
descending anahtar sözcüklerinden faydalanmaktayız. Kodu bu şekilde
denediğimizde aşağıdaki gibi bir ekran çıktısını elde ederiz.
Sorgu 3: Fiyatı 1000 ile 1500 birim
arasında olan ürünleri isimlerine göre tersten sıralayarak elde
etmek.
Console.WriteLine("\nFiyatı 1000 ile 1500 arasında olan
ürünlerin Name alanına göre tersten sıralanmış listesi\n");
var resultSet3=from
p in products
where
p.ListPrice>=1000 && p.ListPrice<=1500
orderby
p.Name descending
select
p;
foreach(Product prd in resultSet3)
Console.WriteLine(prd.ToString()); |
Sorgu 2’ dekine benzer şekilde yazılan
bu kod parçasında tek fark && (ve) operatörünün kullanılmasıdır. Kod
çalıştırıldığında aşağıdaki ekran görüntüsündekine benzer bir sonuç
elde ederiz. Bu seferki sorgu cümlemiz ListPrice alanı için bir
değer aralığı belirlemekte ve bu kritere uyan tüm ürünleri elde
etmemizi sağlamaktadır.
Sorgu 4: Urunler listesindeki
elemanları elde ederken isimsiz bir tipten yararlanmak.
C# 3.0 beraberinde isimsiz tip
(Anonymous Type) adı verilen yeni bir kavram ile birlikte
gelmektedir. Diyelim ki LINQ ifadesi sonrasıda çekilen veri kümesi
içerisindeki elemanları taşıyan yeni bir tipi kullanmak istemiş
olalım. Çok doğal olarak, sorgulamak istediğimiz veri kümesi ne
olursa olsun, önceden planlamadığımız şekilde bir tipe ihtiyacımız
olması doğaldır. İşte isimsiz tip bize bu konuda yardımcı
olabilmektedir. Örneğimizde bunun basit bir kullanımı
gösterilmektedir. Dikkat ederseniz, Product tipine ait Name ve
ListPrice alanlarını sırasıyla UrunAdi ve Fiyat olarak taşıyan yeni
bir tip tanımlanmış ve foreach iterasyonu içerisinde kullanılmıştır.
(İsimsiz tipler aslında tanımlandıkları yerde oluşturulan tipler
olarak da düşünülebilir. Dolayısıyla proje derlendiğinde aşağıda
karşılaşılan satır için yeni bir tip CIL tarafına yazılmaktadır.)
Console.WriteLine("\nSelect sorgularında Anonymous Type
Kullanımı\n");
var resultSet4=from
p in products
select
new {UrunAdi=p.Name,Fiyat=p.ListPrice.ToString("C2")};
foreach(var prd in resultSet4)
Console.WriteLine(prd.UrunAdi+"
"+prd.Fiyat); |
Örneğimizi çalıştırdığımızda
aşağıdakine benzer bir sonuç elde ederiz.
Sorgu 5: Sql’ de Join sorgusu olurda
LINQ içerisinde olmaz mı?
Hepimiz Sql tarafında farklı tabloları
birleştirmek için Join ifadelerinden faydalanırız, faydalanmaktayız.
Aynı özellik LINQ ile, .Net platformuna da taşınmıştır. İşte aşağıda
örnek bir sorgu. Bu sorguda products ve subCategories isimli
değişkenlerde tutulan koleksiyonların içerdikleri verileri
ProductSubCategoryId alanlarının değerlerine göre birleştiriyoruz. Elde edilen
sonuç kümesinde, her iki koleksiyonda da var olan özelliklerden
kombine edilecek yeni bir tip olsa hiç de fena olmaz aslında. İşte
isimsiz tipimizin devreye gireceği yer burası olacaktır. (Bu tip bir ihtiyacı
birde LINQ eklentilerini kullanmadan yapmayı
denersek, sorgu ifadelerinin gelecekte hayatımızı oldukça
kolaylaştıracağını daha kolay anlayabiliriz.) Birleştirme
operasyonu için join anahtar kelimesinden yararlanılmaktadır.
on anahtar kelimesinden sonra ise bildiğimiz kriter
uygulaması gerçekleştirilmektedir.
var
resultSet6=from
prd in products
join ctg in
subCategories
on
prd.ProductSubCategoryId equals ctg.ProductSubCategoryId
select
new{prd.ProductId,prd.Name,prd.ListPrice};
foreach(var p in resultSet6)
Console.WriteLine(p.ToString()); |
Programımızın ekran çıktısı
aşağıdakine benzer olacaktır.
Ekrandaki çıktı tesadüf değildir.
İsimsiz tiplerin ToString metodunun bir sonucudur.
 |
Bir isimsiz tip
tanımlandığında bu tip için CIL tarafına eklenen kodlar
içerisinde ToString metodu ezilip yukarıdakine benzer bir string
döndürmesi sağlanmıştır. Bu kodu herhangibir decompiler aracı ile
açtığınızda da görebilirisiniz.
 |
Sorgu 6: Urunler listesini alt
kategorilere göre gruplamak, her bir gruptaki toplam ürün sayısı,
ortalama, en yüksek, en düşük fiyatları bulmak.
Böyle bir sorgu için öncelikle
ürünleri, alt kategorilerine göre gruplamamız gerekmektedir. Sonra
gruplanan veri kümesi üzerinde bazı gruplama fonksiyonlarını
kullanmalıyız. Bu cümleleri sarfettikçe aslında bir T-Sql sorgusunu
ifade etmeye çalıştığımı düşünüyorum. Ama artık Sql değil LINQ
tarafında ve daha tanıdık topraklardayız. Öyleyse hiç vakit
kaybetmeden örnek kodumuzu aşağıdaki gibi geliştirelim.
var result7=from
prd in products
group prd by
prd.ProductSubCategoryId into g
orderby g.Key
select new{
Kategori=g.Key
,UrunSayisi=g.Count()
,ToplamFiyat=g.Sum(prd=>prd.ListPrice)
,EnDusuk=g.Min(prd=>prd.ListPrice)
,EnYuksek=g.Max(prd=>prd.ListPrice)
,OrtalamaFiyat=g.Average(prd=>prd.ListPrice)
};
foreach(var result in result7)
{
Console.WriteLine("Kategori Id
{0}",result.Kategori.ToString());
Console.WriteLine("\t Toplam Ürün Sayısı
{0}",result.UrunSayisi.ToString());
Console.WriteLine("\t Toplam Birim Fiyat
{0}",result.ToplamFiyat.ToString("C2"));
Console.WriteLine("\t En Düşük Birim Fiyat
{0}",result.EnDusuk.ToString("C2"));
Console.WriteLine("\t En Yüksek Birim Fiyat
{0}",result.EnYuksek.ToString("C2"));
Console.WriteLine("\t Ortalama Fiyat
{0}",result.OrtalamaFiyat.ToString("C2"));
Console.WriteLine();
} |
İlk olarak group anahtar
sözcüğünü kullanarak products içerisindeki Product tiplerini
ProductSubCategoryId alanlarına göre gruplayacağımızı ve
grupladığımız verileri g takma isimli tip içerisinde saklayacağımızı
belirtiyoruz. Hatta elde edilen sonuç kümesini, grupladığımız
verilerin Key özelliğine göre (ki burada Key özelliği
ProductSubCategoryId alanının değerini işaret etmektedir)
sıralatmaktayız. Sıralatma işlemi için bildiğimiz orderby
anahtar kelimesinden faydalanıyoruz. Sonrasında ise yine bir isimsiz tip karşımıza
çıkıyor ki sonuç kümesinde üretilen satırları farklı bir nesne örneği olarak kullanabilmek için tam
aradığımız yapı.
Burada dikkate değer bazı noktalar da vardır. Özellikle
gruplama fonksiyonlarının nasıl kullanıldığına dikkat edelim. Burada
=> gibi bir operatörle karşılaşmaktayız. Bu operatör Lambda operatörü
olarak adlandırılan ve C# 3.0 ile birlikte gelen bir yeniliktir.
Gruplama fonksiyonları aslında, elde edilen küme içerisindeki
elemanları dolaşıp bunlar üzerinde gerekli fonksiyonları
çalıştıracak şekilde tasarlanmışlardır. Örneğin
g.Sum(prd=>prd.ListPrice) çağrısı, sonuç kümesindeki prd takma
isimli her bir Product tipini dolaşıp ListPrice alanlarını toplayarak
bir sonuç üretmek üzere tasarlanmıştır. Diğer gruplama
fonksiyonlarıda buna benzer şekilde çalışmaktadır. Sonuç olarak
örnek kodumuz çalıştırdığımızda aşağıdakine benzer bir ekran çıktısı elde ederiz.
Sorgu 7: Urunler içerisinde baş
harfi H olanların liste fiyatına göre tersten sıralanmış halini
seçip bir diziye taşımak.
Sanırım, LINQ ifadeleri sonrası elde
edilen sonuç kümelerini işe yarayabilecek başka tipte nesnelere
aktarabilmek oldukça işe yarar bir fonksiyonellik olurdu. LINQ bu amaçla
elde edilen sonuçların bir diziye (Array), List veya
Dictionary
koleksiyonlarına aktarılmasını sağlayan fonksiyonelliklerde
içermektedir. Örneğin aşağıdaki kod parçası, products koleksiyonunda
baş harif H olan ürünlerin liste fiyatına göre tersten sırlanmış
halinin bir diziye aktarılmasını sağlamaktadır. Baş harfe göre
karşılaştırma yapabilmek için indeksleyici operatörünü Name alanı
üzerinde nasıl kullandığımıza dikkat edelim. Sonuçta Name alanı
string tipte bir değişkendir ve bir karakter dizisini işaret
etmektedir. Bu nedenle C# dilinin tüm sürümlerinden bildiğimiz gibi
0 indisli eleman aslında Name alanının işaret ettiği verinin birinci
karakteri olacaktır.
var result8=from
prd in products
where
prd.Name[0]==’H’
orderby
prd.ListPrice descending
select
prd;
var result9=result8.ToArray();
for(int i=0;i<result9.Length;i++)
Console.WriteLine(result9[i].ToString()); |
Burada başrol oyuncumuz ToArray
metodudur. ToArray metodu, elde edilen sonuç kümesinin bir diziye
aktarılmasını sağlar. Böylece sonuç kümesindeki elemanlara indeks
numaraları yardımıyla erişmemizde mümkün olmaktadır. Diğer taraftan
bir dizinin sunacağı avantajları değerlendirme şansınada sahip
olabiliriz. Aynı işlemleri LINQ
olmadan yapmaya çalışırsak, yukarıdaki kod parçasına dair yüzümüzde
bir tebessüm oluşmaması için hiç bir neden kalmayacaktır.
Uygulamanın çalışmasının sonucunda aşağıdakine benzer bir ekran
görüntüsü elde ederiz.
Sorgu 8: Join ile birleştirilmiş
bir sorgu sonucunu generic Dictionary koleksiyonuna aktarmak.
Join sorgusu ile urunler ve
altKategorileri birleştirdiğimizi düşünelim. Bu sonuç kümesinde
ProductSubCategoryId alanı Key ve Product nesne örnekleride
Value
olacak şekilde bir Dictionary koleksiyonu oldukça işimize
yarayabilir. Bildiğiniz gibi Dictionary bazlı koleksiyonlar
(Hashtable<>, Dictionary<>, Hashtable vb...) verileri key-value
çiftleri şeklinde tutmaktadırlar. Dolayısıyla özellikle
birleştirilmiş veri kümelerinde elde edilen verileri key ve value
olacak şekilde tutmak işe yarayabilir. Bunu gerçekleştirmek için aşağıdaki gibi bir kod
parçasını kullanabiliriz.
var result11=from
prd in products
join ktg
in subCategories
on
prd.ProductSubCategoryId equals ktg.ProductSubCategoryId
select
new {Kategori=ktg.Name,Urun=prd};
var result12=result11.ToDictionary(ktgName=>ktgName.Urun.ProductId);
IEnumerator<int> numerator=result12.Keys.GetEnumerator();
while(numerator.MoveNext())
{
var
currentProduct=result12[numerator.Current];
Console.WriteLine(currentProduct.Urun.ProductId.ToString()+"
"+currentProduct.Urun.Name+"
"+currentProduct.Urun.ListPrice.ToString("C2")+"
"+currentProduct.Kategori);
} |
Bu sefer başrol oyuncumuz ToDictionary
metodudur. Yanlız metodumuz parametresine dikkat edelim. Burada
ktgName adıyla her bir urunun ProductId değerleri alınmakta ve
Dictionary bazlı koleksiyonun içerisindeki anahtarlara (key)
atanmaktadır. Değer (Value) kısmında ise sorgu sonucu elde edilen
tipler yani Kategori ve Urun alanlarından oluşan isimsiz tiplerimiz
eklenmektedir. Son olarak test amacıyla elde edilen Dictionary
koleksiyonu içerisindeki anahtarlarda bir numarator yardımıyla
dolaşılmaktadır. Burada bildiğimiz ileri yönlü iterasyon deseni
uygulanmaktadır. Aslında uygulamayı debug edersek ve result12
değişkenine QuickWatch penceresinden bakarsak, sorgu
sonuçlarının gerçektende key-value çiftleri şeklinde eklendiği
generic bir Dictionary koleksiyonu ile karşılaşmış oluruz.
Uygulamamızı çalıştırdığımızda ise
aşağıdakine benzer bir çıktı elde ederiz.
Sonuç kümelerini Dictionary
koleksiyonlarına nasıl alabiliyorsak List tipinden generic
koleksiyonlarada alabiliriz. Tek yapılması gereken başrol oyuncusunu
değiştirmek olacaktır. Yani
ToDictionary yerine ToList metodunu kullanamak.
Sorgu 9: Ürünler içerisinde kaç
farklı liste fiyatı olduğunu bulup bunları küçükten büyüğe doğru
elde etmek.
Eminimki Sql bilen herkes bu iş için
distinct operatörünün kullanılması gerektiğini söyleyecektir.
Aynı operatör LINQ içerisinde yer almaktadır. Örneğin, ürünlerin
tutulduğu koleksiyon içerisindeki liste fiyatlarını tekrarsız olarak
elde etmek istediğimizi düşünecek olursak aşağıdaki kod parçasından
faydalanabiliriz.
var result13=(from
prd in products
orderby
prd.ListPrice
select
prd.ListPrice).Distinct();
foreach(var result in result13)
Console.WriteLine(result.ToString()); |
Dikkat ederseniz Distinct
metodunu kullanmadan önce, tüm LINQ ifadesi paranetez içerisine
alınmıştır. Nitekim Distinct operasyonu elde edilen sonuç kümesi
üzerinden uygulanmaktadır. Kodun çalışması sonucu programın çıktısı
aşağıdaki ekran görüntüsündekine benzer olacaktır.
Sorgu 10: Ürünleri önce adlarına
göre küçükten büyüğe sonrada liste fiyatlarına göre büyükten küçüğe
sıralatarak elde etme.
Tipik olarak bahsettiğimiz, birden
fazla alan üzerinde Order By işlemini uygulamaktan başka bir şey
değildir. Bunu gerçekleştirmek için, LINQ ifadelerinde orderby
operatöründen faydalanabiliriz. Aşağıdaki kod parçası bu işlemi
gerçekleştirmektedir.
var result17=from
prd in products
orderby
prd.Name,prd.ListPrice descending
select
prd;
foreach(var result in result17)
Console.WriteLine(result.ToString()); |
Dikkat ederseniz orderby
anahtar kelimesinden sonra, sıralama için ele alınacak alanlar
virgül ile ayrılarak yazılmıştır. Bununla birlikte liste fiyatına
göre tersten sıralatma yaptırmak istediğimiz için descending
anahtar sözcüğünden yararlanılmıştır. Özellikle kendi
geliştirdiğimiz tipleri bir koleksiyonda kullandığımızda ve bu
koleksiyon içerisindeki elemanları sıralatmak istediğimizde,
genellikle IComparer yada IComparable gibi arayüzlerin
ilgili sınıflara uygulanmasını sağlamamız gerekir. Oysaki LINQ ile
bu tarz bir ihtiyaç çok daha kolay bir şekilde ele alınabilmektedir.
Programı çalıştırdığımızda aşağıdakine benzer bir ekran çıktısı elde
ederiz. Dikkat ederseniz her ürün alfabetik olarak sıraya
dizildikten sonra her ürün için ilk harflerine göre kendi içerisinde
liste fiyatına göre tersten sıralanmıştır.
Sorgu 11: Ürünlerin isimlerini
karakter uzunluklarına göre tersten sıralayarak elde etme.
Bu oldukça enteresan olacak. products
koleksiyonu içerisindeki her bir Product tipinin Name alanlarını ele
alacağız. Bunların karakter uzunluklarına göre tersten
sıralatacağız. İşte bu eğlenceli sorgunun LINQ karşılığı.
var result18=from
prd in products
orderby
prd.Name.Length descending
select
new{UrunAdi=prd.Name,ListeFiyati=prd.ListPrice};
foreach(var result in result18)
Console.WriteLine(result.UrunAdi); |
Dikkat ederseniz tek yaptığımız
orderby anahtar kelimesinden sonra prd örneklerinin Name
alanlarının Length özelliklerini ele almak. descending
anahtar kelimeside tersten sıralatma işleminin gerçekleştirilmesini
sağlıyor. Kodu çalıştırdığımızda gerçektende isimlerin uzunluklarına
göre azalan bir formasyonda sıralandığını görebiliriz.
Bu makalemizde 11 değişik sorguda
LINQ’ yu daha yakından tanımaya çalıştık. Makalemizin başında
belirttiğimiz gibi LINQ içerisinde oldukça fazla sayıda operatör yer
almaktadır. Anders Hejlsberg, LINQ teknolojilsini özellikle
veritabanı programcılığı yapanların dil içerisindede aynı felsefeyi
kullanabilmeleri için geliştirildiğini belirtmiştir. Gerçektende
yukarıdaki dil içi sorgular buna verilebecek örneklerden sadece bir
kaçıdır. İlerleyen makalelerimizin birisinde diğer operatörleride
ele almaya çalışacağız. Böylece geldik bir makalemizin daha
sonuna. Bir sonraki makalemizde görüşmek dileğiyle hepinize mutlu günler
dilerim.
Örnek Uygulama İçin
Tıklayınız.Burak Selim ŞENYURT
selim@bsenyurt.com
Makale:
LINQ : Daha Fazla Sorgu .NET 3.0 ve .NET 3.5 Özel Bölümü Burak Selim Şenyurt
|
|
ŞUB 23
2007 |
Çok güzel bir makale daha. Teşekkürler. |
|
|
Sayfalar :
|
|
|
|
|
|
|
-
-
Eklenen Son 10
-
Bu Konuda Geçmiş 10
Bu Konuda Yazılmış Yazılmış 10 Makale Yükleniyor
Son Eklenen 10 Makale Yükleniyor
Bu Konuda Yazılmış Geçmiş Makaleler Yükleniyor
|
|
|
|