Connection (Bağlantı) Nesnesi
ADO.NET''in programcıya sunduğu veri erişim mimarisinden
href="/post/net-te-veri-erisimi-ado-net/">.NET''te Veri Erişimi :
ADO.NET başlıklı yazımızda bahsetmiştik. Belirttiğimiz gibi, ADO.NET,
bağlantısız veri operasyonlarına ve verinin standart XML ifadesine tam destek
veriyor.
ADO.NET''in veri kaynağıyla canlı ilişkide olan tarafını .NET
Veri Sağlayıcısı oluşturuyor. Bu sağlayıcı, veri kaynağına gönderilecek her
türlü komut, ve ondan dönecek her türlü yanıt için bir köprü vazifesi görüyor.
Tüm bu operasyonlar için, bu sağlayıcının aktif bir bağlantısı olması gerekiyor.
İşte bu bağlantı, Connection nesnesiyle temsil ediliyor. Connection
nesnesi, ADO.NET''in en temel nesnesi.
Her veri sağlayıcısı, kendine özgü
gerçeklenmiş bir bağlantı nesnesi sunmak durumunda. .NET ile gelen OLE DB .NET
sağlayıcısının sunduğu bağlantı nesnesi
class=CodeInText>OleDbConnection. SQL Server .NET veri sağlayıcısının
bağlantı nesnesi ise
class=CodeInText>SqlConnection. Her iki nesnenin de kullanımı genel
olarak aynı. Yazımızda her iki sağlayıcı için de bağlantı örnekleri vereceğiz.
SqlConnection
Microsoft SQL Server 7.0 ve üst
sürüm veritabanlarına erişmek için class=CodeInText>System.Data.SqlClient aduzayı altındaki class=CodeInText>SqlConnection nesnesini kullanıyoruz. Bu bağlantı
nesnesi (daha doğrusu nesneyi sunan sağlayıcı), sadece SQL Server için
tasarlandığı için başka bir veritabanı erişiminde kullanamıyoruz. SQL
Server''in daha alt sürümlerine erişim içinse eskiden olduğu gibi yine OLE DB
kullanılacak. Peki 7 ve üst versiyonlarında neden ayrı bir sağlayıcı kullanmamız
gerekiyor? Aslında böyle bi zorunluluk yok. OLE DB hala bir seçenek. Ancak
veritabanı erişimi gibi masraflı bir işte daha yüksek performans
arzuluyorsak, tercihimiz SQL Server .NET veri sağlayıcısı olmalıdır. Çünkü bu
sağlayıcı, SQL Server ile TDS (Tabular Data Stream) paketleri
seviyesinde, yani SQL Server''in anladığı dilde haberleşiyor. Böylece OLE
DB gibi bir tercümanı direk saf dışı bırakmış oluyorsunuz. .NET
dokumantasyonunda bu durum şöyle çizilmiş:
Uygulamanızı hâlâ
veritabanından bağımsız yapmak istiyorsanız, çok katmanlı mimariyi iyi
planlamalı ve gerçeklemelisiniz. Veya ilerde konularımız arasında olacak class=CodeInText>System.Data aduzayı bünyesindeki sağlayıcılar için
yazılmış arabirimlerden (IDbConnection, IDbCommand, IDataReader, ..) yararlanmak
da bir çözüm olacaktır.
Şimdi SQL Server 2000 üzerindeki ünlü
Northwind veritabanına bağlantı kuracağımız, bir konsol uygulaması
yazalım:
| SqlConnectionOrnegi.cs | |
class=cs_c>// gerekli aduzaylarını bildirelim. // SQL Provider''i System.Data.SqlClient aduzayı temsil ediyor. class=cs_k>using System; using System.Data.SqlClient; namespace Evcil.NET { public class CBaglanti { public class=cs_k>static void Main() { // bağlantı cümlesini oluşturalım. // OLEDB bağlantı cümlelerinden farklı olarak, // Provider değeri belirtilmediğine dikkat edin string sBaglantiCumlesi = "Server=(local); User id=sa; Password=; Database=Northwind"; // SqlConnection tipindeki bağlantı nesnemizi, class=cs_c>// SqlConnection sınıfının, bağlantı cümlesini parametre alan // yapılandırıcısı (constructor) ile oluşturuyoruz. SqlConnection oConn = new SqlConnection(sBaglantiCumlesi); // bağlantımızın kurulması oConn.Open(); Console.WriteLine( class=cs_s>"Northwind ile baglanti kuruldu"); class=cs_c>// .... burda Northwind üzerinde class=cs_c>// istediğiniz operasyonları yaptığınızı varsayalım. // işimiz bitince bağlantıyı "kesinlikle" kapatmalıyız. oConn.Close(); Console.WriteLine( class=cs_s>"Northwind ile baglanti kesildi"); } } } | |
Neler
yaptığımıza biraz daha yakından bakalım. Başlangıçta, konsola yazı yazmak için
gereken class=CodeInText>Console sınıfının bulunduğu class=CodeInText>System aduzayını ve class=CodeInText>SqlConnection sınıfının bulunduğu class=CodeInText>System.Data.SqlClient aduzayını kullanacağımızı
derleyiciye class=CodeInText>using ayrılmış kelimesiyle bildirdik. Bu bildirimi
yapmasak da olur; ama o zaman bahsedilen sınıfları, her seferinde aduzayı ile
birlikte (Fully-Qualified) yazmak zorunda kalırız: class=CodeInText>System.Data.SqlClient.SqlConnection . Hangisi
kolayınıza(!) geliyor?
Kendimize has bir aduzayı ve sınıf tanımı
yaptıktan sonra, bağlantı denememizi, bağımsız (stand-alone)
uygulamamızın giriş noktası (entry point) olacak class=CodeInText>Main() rutinimizde yazacağız. Burda "Bağlantı
Cümlesi" diye bir kavram görüyoruz. Bağlantı cümlesi, OLE DB''den gelen bi
kavramdır. Bir OLE DB sağlayıcısı üzerinden bir veritabanına erişimle ilgili her
türlü detay, daha genel bir ifadeyle bir "bağlantı" ile ilgili her detay
bağlantı cümlesinde ifade edilir. Bu cümle anahtar/değer çiftlerinin (;) noktalı
virgül ile birleştirilmiş halidir. İşte örnek bir bağlantı cümlesi:
style="MARGIN-TOP: 4px; MARGIN-BOTTOM: 4px; MARGIN-LEFT: 4px">Provider=SQLOLEDB.1;Integrated Security=SSPI;Persist Security Info=False;Initial Catalog=Northwind;Data Source=127.0.0.1 |
Siz
de kolayca bir OLE DB bağlantı cümlesi oluşturmak isterseniz boş bir metin
dosyasının uzantısını .udl yapın. Dosyanın simgesinin değiştiğini
göreceksiniz. Dosyayı çift tıkladığınızda, "Data Link Properties"
başlıklı sihirbaza benzer bir Windows uygulaması açılacak. Burdaki seçenekleri
kullanarak geçerli bir bağlantı cümlesi oluşturursanız önünüze bir seçenek daha
çıkar: OLEDB bağlantısında, parametre olarak bağlantı cümlesi yerine bu dosyanın
yolunu verebilirsiniz. Böylece bağlantı detayınızı harici bir dosyada saklamış
olursunuz. Ne kadar faydalı olduğu tartışmalıdır.
Şimdi, class=CodeInText>SqlConnection nesnesi için bağlantı cümlesi oluştururken
dikkat etmemiz gereken bir nokta var, ondan bahsedelim. Yukarıda verdiğim
bağlantı cümlesi örneği OLE DB içindi. OLE DB bağlantı cümlelerinde class=CodeInText>Provider anahtarı ile sağlayıcı seçimi yapmamız
gerekiyor. Eğer yapmazsak varsayılan sağlayıcı olan "OLE DB Provider for ODBC
Drivers" i seçmiş oluyoruz. Bu tür bir seçim yapmamızın nedeni OLE DB API
katmanının birbirinden çok farklı veri kaynaklarına erişimi mümkün kılması.
Bunun için de, bizden bağlanacağımız veri kaynağına uygun bir Provider
(sağlayıcı) seçmemizi bekliyor. Ancak class=CodeInText>SqlConnection ile kuracağımız bir bağlantı için
oluşturacağımız cümlede class=CodeInText>Provider anahtarını kullanmıyoruz. Çünkü sadece
SQL Server''e bağlanacağız ve bir "Provider" seçimi yapma hakkımız
yok.
Bağlantı cümlesinde anahtarların sırası önemli değildir. Geleneksel
olsun diye ilk önce class=CodeInText>Server anahtarına bir değer atadık. ( class=CodeInText>Server yerine Data
Source anahtarı da kullanılabilir.) Yerel SQL Server''e bağlanacaksak
anahtara class=CodeInText>"(local)" (veya class=CodeInText>"localhost", class=CodeInText>"127.0.0.1", ..) değerini veriyoruz. Buraya uzaktaki bir
SQL Server''in IP adresini de yazabiliriz. Daha sonra SQL Server Login
bilgilerimizi belirtiyoruz. SQL Server''a iki türlü login olabiliriz. Birincisi
SQL Server Doğrulaması ile. İnternet uygulamaları için en uygun olanı
budur. Bu tür girişte bir kullanıcı adı ve parola belirtiriz. İkincisi ise
Bütünleşik Windows Doğrulaması''dır. Bu seçenekte ise, SQL Server
Windows''a giriş yaptığımız login bilgisine göre doğrulama yapar. Bağlantı
cümlesinde entegre Windows doğrulamasını kullanmak istersek user id ve password
anahtarları yerine class=CodeInText>"Integrated Security = SSPI; " anahtar/değer çiftini
belirtmeliyiz. (veya "Trusted Connection = True;")
Sonra SQL Server
üzerindeki veritabanlarından birini seçmek istiyoruz. Bunun için de class=CodeInText>Database (veya class=CodeInText>Initial Catalog) anahtarını kullanıyoruz. Böylelikle
bağlantı ile ilgili detayları verdiğimiz bir cümleyi oluşturmuş olduk. Bunu bir
string değişkene atadık.
class=CodeInText>SqlConnection tipinde deklare ettiğimiz referansı ( class=CodeInText>oConn), class=CodeInText>SqlConnection''un bağlantı cümlesini parametre alan
yapılandırıcısı ile yarattığımız nesneye bağladık. Bağlantı cümlesini, nesneye
daha sonra da atayabilirdik ama kolaylık olsun diye, daha yapılandırıcıda iken
bu işi hallettik.
alabilecekleri değerler ile ilgili ayrıntılı açıklamayı lokal .NET Framework SDK
dokumantasyonunda veya href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpref/html/frlrfSystemDataSqlClientSqlConnectionClassConnectionStringTopic.asp"
target=_blank>burada bulabilirsiniz.
Bağlantı nesnemizi
oluşturduk. Hafızada (heap''te) bu nesne için bir yer ayrıldı. Ancak tüm bunlar,
"bağlantı cümlesinde" bahsini geçtiğimiz SQL Server veritabanı ile fiziksel bir
bağlantı kurmuş olduğumuz anlamına gelmiyor. Şimdilik sadece niyetlendik. Bu
bağlantının kurulması için bağlantı nesnemizin class=CodeInText>Open() metodunu işletiyoruz. Eğer hiç bir problem yoksa,
bağlantınız kurulacak ve bağlantı nesnemizin class=CodeInText>State (vaziyet) özelliği class=CodeInText>ConnectionState.Open (açık) duruma gelecektir. Artık
veri kaynağı ile oConn nesnesi üzerinden canlı bir bağlantımız vardır ve
sağlayıcının diğer nesneleri ile (SqlCommand, SqlDataReader, SqlDataAdapter) bu
canlı bağlantı üzerinden istediğimiz manipulasyon operasyonlarını
gerçekleştirebiliriz.
Bu yazımızda sadece bağlantı nesnesi üzerinde
odaklanmak istediğimiz için, hiç bir işlem yapmadan bağlantımızı kapatacağız. Bu
iş için de parametresiz basit bir metodumuz var: class=CodeInText>Close(). Veritabanı bağlantısı masraflı (yani sistem
için zahmetli) bir iş olduğundan, işimizi en kısa sürede halledip bekletmeden,
aktif bağlantıyı kapatmayı unutmamalıyız. Eğer bunu unutursak, bağlantımız belli
bir zaman aşımı süresi kadar açık kalacaktır.
Örnek uygulamayı aşağıdaki
komutu kullanarak derleyebilirsiniz.
C:>csc /r:System.dll,System.Data.dll SqlConnectionOrnegi.cs |
Ve
uygulamayı çalıştıralım:
Görüldüğü gibi bir SQL
Server veritabanına bağlantıyı kolayca kurabiliyoruz. Burada belki de üzerinde
durulması yerinde olacak bir konu var: Bağlantı cümlesinin yeri. Yazdığımız
örnekte bağlantı cümlesini hiç bir kaygı duymadan kodumuzun içine gömdük.
Bağlantı cümlesinde yapılacak bir değişiklik için (örneğin SQL Server''in
adresinin değişmesi durumunda) uygulamayı yeniden derleme ihtiyacı doğacağı
açıktır. Bağlantı cümlesini uygulamadan ayrı bir noktada tutmak hem merkezi bir
yönetim hem de esneklik sağlayacak. Elbette bunun düz metin dosyası olması, bir
güvenlik sıkıntısı da doğuracak. Ancak ASP.NET uygulamalarının yapılandırma
dosyaları class=CodeInText>web.config, bu tür kayıtlar için çok ideal bir yer.
Çünkü bu yapılandırma dosyaları düz yazı dosyaları olmalarına rağmen ASP.NET
motoru tarafından ziyaretçilere sunulmuyor. Tıpkı class=CodeInText>.ascx uzantılı dosyalar gibi. Bağlantı cümlesinin
ulaşılabilir olması, dosya özellikle SQL Server login bilgisi içeriyorsa çok
riskli olacaktır.
OleDbConnection
class=CodeInText>OleDbConnection nesnesi, class=CodeInText>System.Data.OleDb aduzayına bağlı, OLE DB .NET verisağlayıcısı üzerinden bir veri kaynağına bağlantı tesis etmemizi sağlar.
Kullanımı aynen yukarıda bahsettiğimiz class=CodeInText>SqlConnection nesnesi gibidir. O nedenle aynı şeyleri
tekrar etmeyeceğiz. Yalnız bu tip bağlantıda, bağlantı cümlesini oluştururken,
hedef veri kaynağına uygun bir Provider seçmemiz gerekecektir. OLE DB
veri sağlayıcısını kullanarak, sistemde OLE DB sağlayıcısı bulunan her veri
kaynağına (SQL Server, Oracle, Access, Indexing Service) bağlanabiliriz.
Biz bir Access veritabanına bağlantı örneği verelim:
| OleDbConnection.cs | |
class=cs_k>using System; using System.Data.OleDb; namespace Evcil.NET { public class COleDb { public class=cs_k>static void Main() { string sBagCumle = @ class=cs_s>"Provider=Microsoft.Jet.OLEDB.4.0; Data Source=C:data.mdb "; OleDbConnection oConn = new OleDbConnection(sBagCumle); class=cs_k>try { oConn.Open(); } class=cs_k>catch ( OleDbException e ) { Console.WriteLine( e.Message ); } class=cs_k>finally { oConn.Close(); } } } } | |
Yaptığımız
her şeyin class=CodeInText>SqlConnection''la birebir aynı olduğunu görüyorsunuz.
Namespace olarak class=CodeInText>System.Data.OleDb kullandığımıza dikkat edin. Bir kaç
nokta daha var. Bağlantı cümlesinde bir Access veritabanının fiziksel yolunu
belirtiyoruz. Peki string ifadenin önündeki " class=CodeInText>@" simgesi de ne işe yarıyor? Biliyorsunuz ki, C''de " class=CodeInText>" (escape) karakterinin kendinden sonra gelen
ilk karakterle beraber özel görevleri var. Bir fiziksel yol yazarken normal " class=CodeInText>" karakterini doğru olarak ifade etmek için iki adet " class=CodeInText>" yazmamız gerekecekti: " class=CodeInText>C:\Data.mdb". İşte string ifadenin önündeki " class=CodeInText>@" karakteri, o stringdeki tüm " class=CodeInText>" karakterlerini ayrıcalıklı olmaktan çıkarıyor. Bir
kolaylık olarak sunulmuş bize.
Kodda, bağlantıda herhangi bir istisna
çıktığı durumda, istisnanın yakalanması ve her hâlukarda bağlantının kapatılması
için class=CodeInText>try/catch/finally yapısının kullanımını da örneklemiş
olduk.
Bitirirken...
Bu
yazıda, veri kaynağı ile sağlayıcı üzerinden nasıl ilişki kurabileceğimizi
gördük. Bu veri tabanı operasyonları için ilk adımdı. Bundan sonra atacağımız
tüm adımlar, kurduğumuz bu ilişki üzerinden yürüyecek.
İyi çalışmalar.