|
|
|
C# 3.0 - İlk Bakışta DLINQ |
|
| Gönderiliyor lütfen bekleyin... |
|
|
Bildiğiniz gibi uzun bir süredir
Microsoft LINQ (.Net Language Integrated Query) adını verdiği ve C# 3.0
ın amacı olan bir projeyi sürdürmekte. Projenin en büyük amacı, özellikle
veri üzerinde yapılabilecek sorgulama tekniklerinin dahada
yaygınlaştırılması ve dil ortamına entegre edilebilmesi. Örneğin LINQ sayesinde IEnumerable<T>
arayüzünü (interface) uygulamış herhanbir tip (type) üzerinde sql
sorgularına benzer ifadeler kullanabilir ve alt kümeler çekebiliriz.
LINQ nun bu özelliklerini kullanabilmek için C# dilinin 3.0 versiyonunda
pek çok yenilik bulunmaktadır. Örneğin var anahtar sözcüğü ile, tip
belirtmeden değişken tanımlayabilmek (var keyword), nesne örneklerini
oluştururken yapıcı metodlara gerek kalmadan başlangıç değerlerini
belirleyebilmek (object initializing), isimsiz tipler oluşturabilmek
(anonymous types) hatta lambda ( => ) isimli yeni bir operatör sayesinde
isimsiz metodları bir adım ileriye götürebilmek vb... mümkündür. Ancak
asıl etki az öncede bahsettiğimiz gibi LINQ ile gelmektedir.
LINQ nun iki farklı uygulama alanı
daha vardır. Bunlar XLINQ - XML Store and Language Integrated Query ve
DLINQ - Database Language Integrated Queries dur. XLINQ ile xml verileri üzerinde dil ile
tümleştirilmiş sorgulama ifadeleri yazmak mümkün olabilmektedir. DLINQ ise bugünkü makalemizin asıl
konusudur. DLINQ ilişkisel
verilerin nesne olarak ifade edilebildiği ortamlar için dil destekli
sorgular kullanabilmemizi sağlamaktadır. Buna göre, bir veritabanına ait
herhangibir tabloyu uygulama tarafında sınıf olarak temsil ettiğimiz durumlarda
(entity), bu
sınıflara ait örneklerin çalışma zamanında veritabanından
doldurulmasını sağlayabilir ve ilgili nesne örnekleri üzerinde LINQ
ifadelerini kullanarak sorgular çalıştırabiliriz. Bunun tersi durumda geçerlidir. Yani
nesnelerin bellekte işaret ettikleri içerikte değişiklik yapıp
veritabanına doğru yönlendirilebilir. Konuyu daha iyi
anlayabilmek için bir örnek üzerinden hareket edelim. Bu örneğimizde
AdventureWorks içerisinde kendi oluşturduğumuz bir tabloyu ele alacağız.
Kullanacağımız örnek tabloyu aşağıdaki script yardımıyla
oluşturabilirsiniz.
USE
[AdventureWorks]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[Calisanlar](
[Id] [int] IDENTITY(1,1) NOT NULL,
[Ad] [nvarchar](50) COLLATE SQL_Latin1_General_CP1_CI_AS NOT
NULL,
[Soyad] [nvarchar](50) COLLATE SQL_Latin1_General_CP1_CI_AS NOT
NULL,
[Maas] [money] NOT NULL,
[GirisTarihi] [datetime] NOT NULL,
[DogumTarihi] [datetime] NOT NULL,
[Unvan] [nvarchar](50) COLLATE SQL_Latin1_General_CP1_CI_AS NOT
NULL,
[Departman] [nvarchar](50) COLLATE SQL_Latin1_General_CP1_CI_AS
NOT NULL,
CONSTRAINT [PK_Calisanlar] PRIMARY KEY CLUSTERED
(
[Id] ASC
)WITH (PAD_INDEX = OFF, IGNORE_DUP_KEY = OFF) ON [PRIMARY]
) ON [PRIMARY] |
DLINQ için kilit nokta DataContext
isimli sınıftır. DataContext sınıfı çalışma zamanında, entity sınıfları ile asıl
veri kaynağının haberleşebilmesine imkan tanır. Çoğunlukla DLINQ
uygulamaları içerisinde, Strongly Typed DataContext sınıfları yer
almaktadır. Bu sınıflar içlerinde, entity sınıflarına ait generic tipler
kullanır. DataContext üzerinden türetme yardımıyla oluşturulan tipler
sayesinde LINQ ifadelerini nesne örnekleri üzerinde çalıştırabiliriz.
Aynı zamanda nesne örnekleri üzerinde yapılacak değişiklikleri
veritabanı tarafına doğru gönderebiliriz. Bu bilgilerden yola çıkarak
hareket ettiğimizde ilk yapmamız gereken aşağıdaki gibi bir entity
sınıfı yazmak olacaktır. Bu sınıf temel olarak Calisanlar tablosundaki
her bir satırı temsil edebilme yeteneğine sahip olacak şekilde
tasarlanmalıdır.

[Table(Name="Calisanlar")]
class
Calisan
{
[Column(Name="Id",Id=true)]
public int Id;
[Column(Name="Ad")]
public string Adi;
[Column(Name="Soyad")]
public string Soyadi;
[Column(Name="Maas")]
public decimal Maasi;
[Column()]
public DateTime GirisTarihi;
[Column()]
public DateTime DogumTarihi;
[Column(Name="Unvan")]
public string Unvani;
[Column(Name="Departman")]
public string Departmani;
} |
DLINQ bir sınıfın, nesne örneği
olduğunda veritabanındaki hangi
tabloya karşılık geldiğini, alanlarının (fields) tablo üzerindeki hangi
kolonlara (columns) denk düştüğünü ve temel özelliklerinin neler
olacağını belirtmemize yarayan nitelikler(attributes) içermektedir.
Örneğin yazmış olduğumuz Calisan isimli sınıfın, veritabanındaki
hangi tabloya karşılık geldiğini Table isimli attribute yardımıyla
belirleyebiliriz. Buna göre Calisan isimli sınıfımız Calisanlar isimli
tabloya ait olacaktır.
 |
Column, Table gibi
nitelikler (attributes) ve biraz sonra göreceğimiz DataContext
sınıfı, System.Data.DLinq isim alanı (namespace) altında yer
almaktadır. |
Benzer şekilde sınıf içerisinde tanımlı
alanların, Calisanlar tablosu üzerinde karşılık geldikleri kolonları
Column isimli nitelik (attribute) yardımıyla belirlemekteyiz. Column niteliği
yardımıyla eşleştirilecek kolon adının ne olacağını belirlemek dışında
başka özellikleride ayarlayabiliriz. Örneğin Id isimli alanın aynı
zamanda identity olacağını Id özelliğine true değeri atayarak
belirlemekteyiz. Benzer şekilde bir alanın veri türünüde DBType
özelliği ile Column niteliği içerisinde ayarlayabiliriz. Aşağıdaki
şekilde Column niteliği içerisinde kullanabileceğimiz diğer özellikler
görülmektedir.

Entity sınıfımızın ardından Strongly Typed DataContext sınıfını yazmamız
gerekmektedir. Bu tip sınıflar
genellikle bir veritabanı içerisindeki tabloların satırlarını temsil
eden entity örneklerine ait toplu veri kümelerini
barındırmak ve yönetmek amacıyla yazılmaktadır. Aşağıdaki kod parçasında yer alan
AdventureWorks isimli sınıfın temel amacı budur.

using System;
using System.Data.DLinq;
namespace UsingDLINQ
{
class AdventureWorks:DataContext
{
public
Table<Calisan>
SirketCalisanlari;
public AdventureWorks(string
conStr)
:
base(conStr)
{
}
}
} |
AdventureWorks isimli sınıfımız
DataContext ten türetilmektedir. Yapıcı metodumuz içerisinde dikkat
edecek olursanız parametre olarak bağlantı bilgisini alıp DataContext
sınıfının ilgili yapıcı metoduna (Constructor) göndermekteyiz.
AdventureWorks isimli sınıfın bir diğer önemli üyesi
SirketCalisanlari dir. Bu üyenin tipi Table dır. Table tipi burada
generic tir ve Calisan sınıfı tipinden örnekler barındırabileceği
belirtilmektedir. Öyleyse biz SirketCalisanlari ile, Calisanlar
tablosunun tüm satırlarını referans edebiliriz. Şimdi gelelim LINQ yu işin içerisine katarak çalışma
zamanında Calisanlar isimli tablodan nasıl sorgulama yapabileceğimize.
Bu amaçla oluşturacağımız LINQ Preview Console uygulaması içerisinde
aşağıdaki kodları yazmamız gerekiyor.
using System;
using
System.Query;
namespace UsingDLINQ
{
class Program
{
static void Main(string[] args)
{
AdventureWorks adw = new AdventureWorks("data
source=localhost;database=AdventureWorks;integrated
security=SSPI");
var
calisanListesi=from clsn in adw.SirketCalisanlari select clsn;
foreach(var c
in calisanListesi)
{
Console.Write(c.Id.ToString());
Console.Write("\t"+c.Adi+" ");
Console.Write(c.Soyadi);
Console.Write("\t"+c.Maasi.ToString());
Console.Write("\t"+c.DogumTarihi.ToString());
Console.WriteLine("\t"+c.Departmani.ToString());
}
}
}
} |
Uygulamamızı çalıştırdığımızda
aşağıdaki ekran görüntüsünde yer alan sonuçları elde ederiz.

Dikkat ederseniz burada C# 3.0 ile
gelen bir kaç yenilik yer almaktadır. Bunlardan birisi var anahtar
sözcüğünün kullanılmasıdır. Bildiğiniz gibi var anahtar sözcüğü ile bir
değişkeni, tipini belirtmeden tanımlayabilir ve kullanabiliriz. İkinci
önemli yenilik ise C# 3.0 ın asıl konusunu oluşturuan LINQ
ifadelerinin kullanılmasıdır. from anahtar sözcüğü ile
başlayan ifademizde AdventureWorks sınıfına ait nesne örneği
içerisinde yer alan Table tipindeki SirketCalisanlari nesne örneği
üzerinden basit bir select sorgusu atılmaktadır. Burada yazım tarzı
T-Sql göz önüne alındığında biraz ters gelebilir. Ancak uygulamacı
gözüyle baktığımızda son derece mantlık bir sorgu cümlesi ortaya
çıkmaktadır. Şimdi sorgumuzu biraz
değiştirip aşağıdaki hale getirelim.
| var
calisanListesi=from clsn in adw.SirketCalisanlari
where
clsn.Departmani=="Yazılım"
select clsn; |
Bu durumda uygulamamızı
çalıştırdığımızda sadece yazılım departmanına ait çalışanları elde
edebiliriz.
 |
Sorgu ifadelerinin doğru
çalışabilmesi için (örneğin where anahtar sözcüğünü
kullanabilmek için) System.Query isim alanını uygulamamıza dahil
etmemiz gerekmektedir. |

Bu durumda sonuç şu şekilde olacaktır.
Şimdi örneğimizi biraz daha geliştirelim ve DLINQ kullanarak ilişkili
verilerin nesnel bazda nasıl sorgulanabileceğini ele almaya çalışalım.
Bu amaçla Sql Server 2005 üzerinde bizim emektar Northwind veritabanını
kullanacağız. Senaryo olarak Categories ve Products tablolarının
birleştirilmiş hallerini (bir başka deyişle join edilmiş hallerini) ele
almaya çalışacağız. Yanlız bu kez bu birleştirilmiş veri kümesini kod
tarafındaki katmanlarda ele alacağız. Bizim için gerekenler öncelikli olarak Categories ve
Products tabloları için birer entity sınıfı. Sonrasında ise yazmış
olduğumuz bu entity sınıfları ile asıl tablolarımız arasındaki ilişkiyi
sağlayacak DataContext ten türemiş bir sınıf. DataContext
tipinden türeteceğimiz bu sınıf içerisinde tablolar arasındaki
ilişkiyide nesnel bazda sağlamamız gerekecektir. Bunun içinde
Association niteliğinden ve EntitySet tipinden yararlanacağız. İlk
olarak entity sınıflarımızı aşağıdaki gibi geliştirelim.

using System;
using
System.Data.DLinq;
namespace UsingDLINQ
{
[Table(Name="Categories")]
class Kategori
{
[Column(Name="CategoryID",Id=true)]
public int KategoriId;
[Column(Name="CategoryName")]
public string KategoriAdi;
private
EntitySet<Urun> m_urunDetay;
[Association(Storage="m_urunDetay",OtherKey="KategoriId")]
public
EntitySet<Urun> UrunDetaylari
{
get { return
m_urunDetay; }
set {
m_urunDetay.Assign(value); }
}
}
[Table(Name="Products")]
class Urun
{
[Column(Name="ProductID",Id=true)]
public int UrunId;
[Column(Name="ProductName")]
public string UrunAdi;
[Column(Name="UnitPrice")]
public decimal BirimFiyat;
[Column(Name="CategoryID")]
public int KategoriId;
private
EntityRef<Kategori> m_kategorisi;
[Association(Storage = "m_kategorisi", ThisKey = "KategoriId")]
public Kategori
Kategorisi
{
get { return
m_kategorisi.Entity; }
set {
m_kategorisi.Entity = value; }
}
}
} |
Buradaki kod parçasında, Kategori ve
Urun sınıfları arasında çalışma zamanında ifade edilebilecek bire-çok
(one-to-many) ilişkide tanımlanmıştır. Kategori sınıfı içerisinde bu işi
UrunDetaylari isimli özellik gerçekleştirmektedir. Özelliğe uygulanan
Association isimli nitelik, bir kategoriye bağlı ürünlerin nerede
saklanacağını storage özelliği yardımıyla belirtmektedir. İkinci
parametremiz ise bire-çok ilişki için gerekli anahtar(key) alanı işaret eder
ki buda ilgili kategorinin id değeri olacaktır. Şimdide DataContext ten
türettiğimiz Strongly Typed tipimizi yazalım.

using System;
using
System.Data.DLinq;
namespace UsingDLINQ
{
class Northwind:DataContext
{
public
Table<Kategori>
Kategoriler;
public
Table<Urun>
Urunler;
public Northwind(string conStr)
: base(conStr)
{
}
}
} |
Dilerseniz daha fazla detaya girmeden
nesnel bazda ifade edebileceğimiz bu ilişkiyi LINQ üzerinden nasıl
kullanabileceğimize bakalım. Bu amaçla programımıza aşağıdaki kod
satırlarını ekleyelim.
Northwind
nrth=new Northwind("data
source=localhost;database=Northwind;integrated security=SSPI");
var sonuclar =
from urn in
nrth.Urunler from ktg in nrth.Kategoriler where urn.KategoriId
== ktg.KategoriId select urn;
var
altSonuclar=from
snc in sonuclar where snc.KategoriId==2 select snc;
Console.WriteLine("\t Join Üzerinden Belirli Kategori Altında
Olanlar...");
Console.WriteLine();
foreach (Urun
u in altSonuclar)
{
Console.WriteLine(u.KategoriId.ToString()+"\t"+u.Kategorisi.KategoriAdi+"\t"+u.UrunAdi+"\t"+u.BirimFiyat.ToString());
} |
Uygulamamızı bu haliyle
çalıştırdığımızda aşağıdaki ekran görüntüsünü elde ederiz. Gördüğünüz
gibi KategoriId değeri 2 olan ürünleri çekebilmekteyiz. Bu amaçla iki
adet LINQ ifadesi kullanılmıştır. İlk ifade aslında Urunler ve
Kategoriler isimli Table nesne örneklerine ait veri kümelerini
KategoriId alanları üzerinden birleştiren ve T-Sql deki Join benzeri bir
işlevselliği sağlayan yapıdadır. İkinci LINQ ifadesinde ise bu Join
yapısı üzerinden KategoriId ye bir alt küme çekilmektedir.

Yapmış olduğumuz örneklerdende
anlayabileceğiniz gibi DLINQ aslında iş katmanında yer alan tiplerin
üzerinden T-Sql tarzında sorguların yapılabilmesini sağlamaktadır. DLINQ
ana konu olarak LINQ ifadelerini kullandığından, çalışma zamanında
bellek üzerinde bulunan nesneler üzerinde istenilen sorgulamalar
yapılabilir. DLINQ kendi içerisinde kayıt düzenleme, transaction
kullanımı gibi daha ileri seviye imkanlara da sahiptir. Bu konular ile
ilgili daha detaylı bilgileri
sitesinden bulabilirsiniz. Bu makalemizde kısaca DLINQ teknolojisine
kısaca bakmaya ve tanımaya çalıştık. Makale içerisinde geçen bilgilerin
çoğunun C# 3.0 ın son hali yayımlanana kadar değişiklik
gösterebileceğini de göz önüne almamız gerektiğini unutmayalım. Bir sonraki makalemizde görüşünceye
dek hepinize mutlu günler dilerim.
Örnek Uygulama İçin Tıklayın.
Burak Selim ŞENYURT
selim@bsenyurt.com
Makale:
C# 3.0 - İlk Bakışta DLINQ C#, Visual C# ve .NET Burak Selim Şenyurt
|
|
KAS 8
2006 |
DLINQi görsel arabirim ile kullanmıştım. Yani projeye add new item ile DLinq Objects ekleyip Server Explorerdan ilgili tabloyu sürükleyip obje üzerine bırakarak. Ancak bu makale sayesinde arka planda olanları daha iyi kavradım. Emeğiniz için Teşekkür ederim. Makale Sadece DLINQi anlatmamış ayrıca C# daki yeniliklere de genel olarak değinmiş. |
|
|
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
|
|
|