Jump to content

Linq: Language Integrated Query - 1


wmismail

Recommended Posts

Yenilikleri kabullenmeme konusunda son derece başarılı insanlar olduğumuz tartışmasız bir gerçek. .NET Framework'un ülkemizdeki kullanım istatistiğini inceleyecek olursak, çok az sayıda firmanın yeniliklere hızlı bir şekilde adapte olduğunu görürken, büyük çoğunluğun "web servisi mi? o da ne, hem güvenli midir vs.vs." gibi yorumlarla gizliden gizliye "önce diğer firmalar bir denesin, sorun yaşamazlarsa biz de geçeriz" stratejisini izlediklerini görüyoruz. Tabi bu tutumun nedenlerini araştırırken tarihsel geçmişimizi inceleyip genetik bazı sonuçlar çıkarmak mümkünse de, yazgeliştir'de yemek tarifi veren ilk kişi olmanın yanında, tarih makalesi yayınlayan ilk kişi olmayı pek arzu etmiyorum..

Konuya dönecek olursak, büyük çoğunluğunuz duymuştur "Linq" kelimesini, duyan çoğunluğun bir kısmı araştırıp, açılımının Language Integrated Query olduğunu, bu araştırmayı yapanlarında bir kısmı ne işe yaradığını, onlarında bir kısmı detaylarını araştırmıştır. Bu makalede amacım Linq'in ne olduğu, ne amaçla tasarlandığı, ne gibi imkanlar sunduğu gibi bazı konuları açıklığa kavuşturmak. Daha sonraki makalelerle ise Linq'i daha detaylıca ele alıyor olacağım.

Lafı çok uzatıp makaleye varoluşu ele alarak başlamaya gerek yok. Object Oriented yazın, yazmayın veri erişimi bugünün uygulamaları ve servisleri için en önemli konu. Veri erişimi için pek çok farklı yöntem kullanıyoruz. Büyük çoğunluk kendi alışkanlıkları doğrultusunda veri erişim katmanları oluştururken, bazı uygulama geliştiricilerse mevcut bazı veri erişim modellerini kullanmayı tercih ediyor. Dikkat etmemiz gereken nokta ise, kullandığımız dilin sunduğu imkanlar doğrultusunda veri erişimini sağlayacak bir yapının ortaya çıkarılmaya çalışılıyor olması. Geldiğimiz noktada veri kaynağı olarak xml ve ilişkisel veritabanları en yoğun kullanılan seçenekler. Linq'in çıkış noktası ise, programlama dilinin özelliklerini kullanarak tek bir veri kaynağına erişmemizi mümkün kulan bir yapı ortaya çıkartmak yerine, daha genel bir yaklaşımla veri erişimini programlama dilinin bir özelliği olarak sunmaktır. Örneğin, C# dilini kullanarak, SQL dili ile yazdıklarımıza benzer, dinamik sql ifadeleri ile elde ettiğimiz esnekliği ve stored procedure'lar ile elde ettiğimiz etkin ve güvenli yapıya benzer bir sorgulamayı, IntelliSense ve compile-time tür denetimi gibi özelliklerle yazabilmek.. Hikaye gibi anlattım, şimdi işte Linq bunları sağlar, buradanda download edip kullanabilirsiniz demeyi isterdim ama, malesef henüz (tam olarak) o noktada değiliz. Ama bu anlattıklarımı Linq neyi amaçlar sorusunun cevabı olarak kabul edebilirsiniz. Aslında bulunduğumuz noktada (yani Framework 3.5 Beta aşamasında) belirttiğim noktaya gelmiş sayılırız ancak tam anlamıyla bu noktadayız diyebileceğimiz tarih, Visual Studio'nun bir sonraki sürümünün (Orcas) yayınlandığı tarihtir.

Pekala, Linq uygulamada bize ne sağlıyor?

Uygulama ile görelim.

1000001385_rowing.jpg

Örnek uygulamamızda Sporcular adında, kürekçi bilgileri içeren bir classımız olacak. Bu classın içinde sporcuya ait ad, soyad, hangi sınıfta yarıştığı, hangi tekne ile yarıştığı (gerçi genellikle bir kürekçi birden fazla tekne ile yarışa çıkar ama işi fazla detaylandırmaya gerek yok) ve doğum tarihi bilgilerini içeren propertyler olacak.

Uygulamamızın arayüzü aşağıdaki gibi olacak:

1000001385_interface-1.jpg

Sporcu classı public class Sporcu

{

public enum TekneTurleri

{

Tek_Çifte,

İki_Çifte,

İki_Tek,

Dört_Çifte,

Dört_Tek,

Sekiz_Tek

}

public enum YarisKategorileri

{

Genc_C,

Genc_B,

Genc_A,

Büyük_B,

Büyük_A,

Kıdemli_A,

Kıdemli_B,

Kıdemli_C,

Hafif_Kilo

}

private string _ad, _soyad;

private YarisKategorileri _yarisKategorisi;

private TekneTurleri _tekneTuru;

private DateTime _dogumTarihi;

public string Ad

{

get { return _ad; }

set { _ad = value; }

}

public string Soyad

{

get { return _soyad; }

set { _soyad = value; }

}

public YarisKategorileri YarisKategorisi

{

get { return _yarisKategorisi; }

set { _yarisKategorisi = value; }

}

public TekneTurleri TekneKategorisi

{

get { return _tekneTuru; }

set { _tekneTuru = value; }

}

public DateTime DogumTarihi

{

get { return _dogumTarihi; }

set { _dogumTarihi = value; }

}

public Sporcu(string Ad, string Soyad, YarisKategorileri yarisKategorisi, TekneTurleri tekneTuru, DateTime dogumTarihi)

{

_ad = Ad;

_soyad = Soyad;

_dogumTarihi = DogumTarihi;

_tekneTuru = tekneTuru;

_yarisKategorisi = yarisKategorisi;

_dogumTarihi = dogumTarihi;

}

}

Uygulama kodlarının daha az karmaşık olması için Sporcu classından nesneler oluşturarak liste olarak bize sunacak bir Sporcular classı oluşturuyorum.

Sporcular classı public class Sporcular : List<Sporcu>

{

public Sporcular()

{

Add(new Sporcu("Kadir", "Sümerkent", Sporcu.YarisKategorileri.Büyük_A, Sporcu.TekneTurleri.Tek_Çifte,Convert.ToDateTime("01.01.1980")));

Add(new Sporcu("Nancy", "Davolio", Sporcu.YarisKategorileri.Büyük_A, Sporcu.TekneTurleri.Tek_Çifte, Convert.ToDateTime("02.02.1980")));

Add(new Sporcu("Andrew", "Fuller", Sporcu.YarisKategorileri.Büyük_A, Sporcu.TekneTurleri.Tek_Çifte, Convert.ToDateTime("03.03.1980")));

Add(new Sporcu("Janet", "Leverling", Sporcu.YarisKategorileri.Büyük_A, Sporcu.TekneTurleri.Tek_Çifte, Convert.ToDateTime("04.04.1980")));

Add(new Sporcu("Margaret", "Peacock", Sporcu.YarisKategorileri.Büyük_A, Sporcu.TekneTurleri.Tek_Çifte, Convert.ToDateTime("05.05.1980")));

Add(new Sporcu("Steven", "Buchanan", Sporcu.YarisKategorileri.Büyük_A, Sporcu.TekneTurleri.Tek_Çifte, Convert.ToDateTime("06.06.1980")));

Add(new Sporcu("Michael", "Suyama", Sporcu.YarisKategorileri.Büyük_A, Sporcu.TekneTurleri.Tek_Çifte, Convert.ToDateTime("07.07.1980")));

Add(new Sporcu("Robert", "King", Sporcu.YarisKategorileri.Büyük_A, Sporcu.TekneTurleri.Tek_Çifte, Convert.ToDateTime("08.08.1980")));

Add(new Sporcu("Laura", "Callahan", Sporcu.YarisKategorileri.Büyük_A, Sporcu.TekneTurleri.Tek_Çifte, Convert.ToDateTime("09.09.1980")));

Add(new Sporcu("Anne", "Dodsworth", Sporcu.YarisKategorileri.Büyük_A, Sporcu.TekneTurleri.Tek_Çifte, Convert.ToDateTime("10.10.1980")));

}

}

Şimdi Formun load olayında, form üzerinde ilgili combobox kontrollerine yarış kategorileri ve tekne türlerini ilgili enumerationlardan yükleyecek ve tüm sporcuların listesini listview'a yükleyecek kodları yazıyorum, aynı zamanda tüm prosedürlerden erişebilmek için sporcular nesnesini prosedürlerin dışında tanımlıyorum:

Form_Load olayı Sporcular sporcular = new Sporcular();

private void Form1_Load(object sender, EventArgs e)

{

comboBox1.DataSource = Enum.GetNames(typeof(Sporcu.TekneTurleri));

comboBox2.DataSource = Enum.GetNames(typeof(Sporcu.YarisKategorileri));

for (int i = 0; i < sporcular.Count; i++)

{

listView1.Items.Add(sporcular.Ad);

listView1.Items.SubItems.Add(sporcular.Soyad);

listView1.Items.SubItems.Add(sporcular.YarisKategorisi.ToString());

listView1.Items.SubItems.Add(sporcular.TekneKategorisi.ToString());

listView1.Items.SubItems.Add(sporcular.DogumTarihi.ToShortDateString());

}

}

Uygulamayı çalıştırdığımda şu aşamada gördüğümüz ekran aşağıdaki gibidir:

1000001385_interface-2.jpg

Şimdi Linq öncesinde bu liste içinde ismi Robet olan sporcunun detaylarını almak istediğimizde yazacağımız (Button1'in Click eventında) koda bir bakalım:

Button1_Click olayı listView1.Items.Clear();

for (int i = 0; i < sporcular.Count; i++)

{

if (sporcular.Ad = textBox1.Text)

{

listView1.Items.Add(sporcular.Ad);

listView1.Items[listView1.Items.Count - 1].SubItems.Add(sporcular.Soyad);

listView1.Items[listView1.Items.Count - 1].SubItems.Add(sporcular.YarisKategorisi.ToString());

listView1.Items[listView1.Items.Count - 1].SubItems.Add(sporcular.TekneKategorisi.ToString());

listView1.Items[listView1.Items.Count - 1].SubItems.Add(sporcular.DogumTarihi.ToShortDateString());

}

}

Gördüğünüz gibi mevcut imkanlarla bu işlemi yapmak için akla gelen yöntemlerden ilki bir for döngüsü kullanmak. Tabi işimiz her zaman bu kadar kolay olmayabilir. Bu kodu sonuçları birden çok kritere göre filtreleyecek ve belirttiğimiz bir property'e göre sıralayacak şekilde güncelleyecek olursak işi epey uzatmış oluruz. Ancak bu detaylı isteğimizi Linq ile kolayca gerçekleştirebiliriz. Şöyle ki:

Button1_Click olayı (Linq ile yazılmış olan) //Sporcu ismine göre arama yapıyoruz

var a = from s in sporcular where s.Ad == textBox1.Text orderby s.Ad descending select s;

//buradan sonrası listview'ı doldurmakla ilgili

listView1.Items.Clear();

foreach (var result in a)

{

listView1.Items.Add(result.Ad);

listView1.Items[listView1.Items.Count-1].SubItems.Add(result.Soyad);

listView1.Items[listView1.Items.Count - 1].SubItems.Add(result.YarisKategorisi.ToString());

listView1.Items[listView1.Items.Count - 1].SubItems.Add(result.TekneKategorisi.ToString());

listView1.Items[listView1.Items.Count - 1].SubItems.Add(result.DogumTarihi.ToShortDateString());

}

Gördüğünüz gibi bu filtrelemeyi sporcular adlı liste içinde yapmak için herhangi bir döngü kullanmadan, sql'e oldukça benzer bir ifade ile oluşturduk ve sonuçları listview'a ekledik. Formumuza Soyad, Tekne Türü ve yarış Kategorisi ile ilgili arama kodlarını da ekleyelim:

Button2_Click olayı (Linq) //Sporcu soyadına göre arama yapıyoruz

var a = from s in sporcular where s.Soyad == textBox2.Text orderby s.Ad descending select s;

//buradan sonrası listview'ı doldurmakla ilgili

listView1.Items.Clear();

foreach (var result in a)

{

listView1.Items.Add(result.Ad);

listView1.Items[listView1.Items.Count-1].SubItems.Add(result.Soyad);

listView1.Items[listView1.Items.Count - 1].SubItems.Add(result.YarisKategorisi.ToString());

listView1.Items[listView1.Items.Count - 1].SubItems.Add(result.TekneKategorisi.ToString());

listView1.Items[listView1.Items.Count - 1].SubItems.Add(result.DogumTarihi.ToShortDateString());

}

Button3_Click olayı (Linq) //Tekne türüne göre arama yapıyoruz

var a = from s in sporcular where s.TekneKategorisi.ToString() == comboBox1.SelectedItem.ToString() orderby s.Ad descending select s;

//buradan sonrası listview'ı doldurmakla ilgili

listView1.Items.Clear();

foreach (var result in a)

{

listView1.Items.Add(result.Ad);

listView1.Items[listView1.Items.Count-1].SubItems.Add(result.Soyad);

listView1.Items[listView1.Items.Count - 1].SubItems.Add(result.YarisKategorisi.ToString());

listView1.Items[listView1.Items.Count - 1].SubItems.Add(result.TekneKategorisi.ToString());

listView1.Items[listView1.Items.Count - 1].SubItems.Add(result.DogumTarihi.ToShortDateString());

}

Button4_Click olayı (Linq) //Yarış kategorisine göre arama yapıyoruz

var a = from s in sporcular where s.YarisKategorisi.ToString() == comboBox2.SelectedItem.ToString() orderby s.Ad descending select s;

//buradan sonrası listview'ı doldurmakla ilgili

listView1.Items.Clear();

foreach (var result in a)

{

listView1.Items.Add(result.Ad);

listView1.Items[listView1.Items.Count-1].SubItems.Add(result.Soyad);

listView1.Items[listView1.Items.Count - 1].SubItems.Add(result.YarisKategorisi.ToString());

listView1.Items[listView1.Items.Count - 1].SubItems.Add(result.TekneKategorisi.ToString());

listView1.Items[listView1.Items.Count - 1].SubItems.Add(result.DogumTarihi.ToShortDateString());

}

Gördüğünüz gibi Linq ile elimizdeki liste içinde filtreleme yapmak için artık programlama dili ile döngüler oluşturup içinde kaybolmak yerine, zaten aşina olduğumuz sql diline oldukça yakın bir sözdizimi ile, son derece esnek ve güçlü bir sorgulama altyapısına sahip durumdayız.

Linq'i denemek, kendini bu konuda geliştirmek isteyenler Visual Studio Orcas'ın Beta sürümlerini veya Orcas Express Edition'ları bu sayfadan bulabilirler.

Bir sonraki makalede Linq'in altyapısını daha detaylı olarak ele alacak ve örneklerimizi geliştiriyor olacağız.

Makalede geliştirdiğim uygulamayı download etmek için burayı tıklayın.

Link to comment
Share on other sites

Yazı dizisinin ilk bölümünde bir collection üzerinde Linq ile küçük işlemler yapmıştık. Bu makalede gerçek hayata hızlı bir geçiş yapıp Linq'i SQL Server ile entegra olarak nasıl kullanabileceğimize bakıyor olacağız. Hızlıca konuya girelim.

LINQ, kullanılan programlama dilinin sözdizimi ve compile-time ortamından uzaklaşmadan, programlama dilinin sunduğu bir özellik olarak ilişkisel veri kaynaklarını sorgulamak için kullanılabilir. Kod adı D-Linq olan bu özellik sayesinde SQL şema bilgisinin CLR metadatasıyla entegrasyonunun sunduğu güçlü bir altyapıya kavuşmuş oluruz. Bu entegrasyon SQL tablo ve view tanımlamalarını CLR türlerine compile ederek tüm .NET dilleri tarafından erişilebilir hale gelmelerini sağlar.

DLinq (Table) ve (Column) adında iki temel attribute sunar. (Table) attributeu bir classa uygulanır ve CLR türünü SQL tablosu veya viewı ile ilişkilendirir. (Column) attributeu ise tüm fieldlara ve/veya propertylere uygulanabilir ve ilgili üyeyi, belirli bir SQL sütunu ile ilişkilendirir. Her iki attributeda SQL-spesifik metadatanın tutulabilmesini sağlamak için çeşitli parametreler sunmaktadır.

Ve örnek:

Çok sıradışı olarak kişi-sipariş örneğinden ilerleyelim.

İşe örnekte kullanacağım tabloları veritabanında (dlinqsample) oluşturarak başlıyorum:

Örneğimizde kullanılacak tabloları oluşturan T-SQL komutları create table Customer (

Name nvarchar(30)primary key not null,

Age int not null,

City nvarchar(15) not null,

VIP bit not null

)

create table Orders (

OrderID int primary key not null IDENTITY (1, 1),

Customer nvarchar(30) not null,

Amount int

)

1000001386_linq2-1.jpgBu tabloların CLR karşılıkları aşağıdaki gibi olacaktır:

 [u]Örneğimizde kullanılacak tabloları oluşturan T-SQL komutları[/u]  [Table(Name="Customer")]
public class Customer
{
[Column(DBType = "nvarchar(30) not null", IsPrimaryKey = true)]
public string Name;
[Column]
public int Age;
[Column]
public string City;
[Column]
public bool VIP;
}

[Table(Name = "Orders")]
public class Orders
{
[Column(DBType = "int not null", IsPrimaryKey = true)]
public int OrderID;
[Column(DBType = "nvarchar(30) not null")] 
public string Customer;
[Column]
public int Amount;
}

Ben tablolara örneklerde kullanmak için bir kaç veri ekledim. (Kodları denediğinizde karşınıza boş ekranlar gelirse bunu sizde yapın (: )

İlk olarak sadece müşteri listesini alacak bir form oluşturalım,

Formun tasarımında sadece bir listbox kontrolü olacak. Formun load olayı ise aşağıdaki gibi olacak:

Veri erişiminde kullandığım class ve formun load olayı public class midLayer : DataContext

{

public Table<Customer> customers;

public midLayer(string connectionString):base (connectionString)

{}

}

private void Form1_Load(object sender, EventArgs e)

{

midLayer m = new midLayer("Data Source=ROOT; Initial Catalog=dlinqsample; User Id=sa; Password=q1w2e3r4t5");

var customerList = from clist in m.customers select clist;

foreach (var c in customerList)

{

listBox1.Items.Add(c.Name);

}

}

Sonuç 1000001386_linq2-2.jpgBen sadece Name özelliğini yazdırdığım için ListBox içinde müşterilerin adlarının listesini görüyoruz.

Şimdi bu müşterilerin verdikleri siparişleri görüntüleyelim:

Aşağıdaki kodda görebileceğiniz gibi midLayer sınıfına bir satır ekleyerek Orders tablosunuda erişilebilir hale getiriyoruz.

midLayer'ın güncellenmiş hali ve sipariş listesi formu (form2) public class midLayer : DataContext

{

public Table<Customer> customers;

public Table<Orders> orders;

public midLayer(string connectionString):base (connectionString)

{}

}

Form2_Load eventı private void Form2_Load(object sender, EventArgs e)

{

midLayer m = new midLayer("Data Source=ROOT; Initial Catalog=dlinqsample; User Id=sa; Password=q1w2e3r4t5");

var orderList = from olist in m.orders select olist;

foreach (var o in orderList)

{

listBox1.Items.Add(o.OrderID.ToString() + "\t" + o.Customer + "\t" + o.Amount.ToString());

}

}

Runtime sırasında Form2'nin görünümü 1000001386_linq2-3.jpgSırada üçüncü formu hazırlayarak bu iki tablodaki verileri bir araya getirmek ve müşteri bazında siparişleri listelemek kalıyor:

Form yüklendiğinde yapacağımız işlem combobox kontrolüne veritabanındaki müşterileri yüklemek:

form3'ün load eventi //müşterileri yüklüyoruz

var customerList = from clist in m.customers select clist;

foreach (var c in customerList)

{ comboBox1.Items.Add(c.Name); }

Form3'ün yüklendiği andaki görünümü 1000001386_linq2-4.jpg ComboBox1'in SelectedIndexChanged olayına ise sorgulamayı yaparak sonuçları görüntüleyecek olan aşağıdaki kodları yazıyoruz. private void comboBox1_SelectedIndexChanged(object sender, EventArgs e)

{

listBox1.Items.Clear();

//müşteri bilgilerini yazdırıyoruz

var customer = from clist in m.customers where clist.Name == comboBox1.SelectedItem.ToString() select clist;

foreach (var c in customer)

{

lblCustomerName.Text = c.Name;

lblCustomerAge.Text = c.Age.ToString();

lblCustomerCity.Text = c.City;

lblCustomerIsVIP.Text = c.VIP.ToString();

}

//sipariş bilgilerini yazdırıyoruz

var OrderHistory = from orderlist in m.orders

join customerlist in m.customers

on orderlist.Customer equals customerlist.Name

into result

where orderlist.Customer == comboBox1.SelectedItem.ToString()

select new { Name = orderlist.Customer, OrderId = orderlist.OrderID, OrderAmount = orderlist.Amount };

foreach (var result in OrderHistory)

{

listBox1.Items.Add(result.OrderId.ToString() + "\t" + result.OrderAmount.ToString());

}

}

Ve comboboxtan seçim yapıldığında karşımıza aşağıdaki görüntü çıkıyor 1000001386_linq2-5.jpgGeldiğimiz noktada Linq'i (daha doğrusu bu makalede DLinq'i) kullanarak SQL Server'a bağlanarak sorgulamalar yaptık ve sonuçları görüntülemeyi gördük. Bir sonraki makalede Linq'in yapısal özelliklerini ele alıyor olacağız.

Link to comment
Share on other sites

Archived

This topic is now archived and is closed to further replies.

  • Recently Browsing   0 members

    No registered users viewing this page.

×
×
  • Create New...