C#’ta Veritabanı İşlemleri (Database Operations with C#) ADO.NET’e Genel Bir Bakış Microsoft VS.NET’te gerçekleştirilmektedir. veritabanı işlemleri ADO.NET ile ADO.NET yazılımcının çeşitli veritabanlarıyla ilgili akla gelebilecek bütün işlemlere müdahale edebilmesi için geliştirilmiş .NET dillerinin hepsiyle birlikte kullanılabilen ortak bir yapıdır. Bu yapı içerisinde çeşitli veritabanı işlemlerini gerçekleştirmeye yönelik pek çok nesne, yöntem ve sınıf mevcuttur. Bu işlemlere örnek vermek gerekirse; Kayıt ekleme, silme, değiştirme, arama, her türlü SQL işlemleri, transaction yönetimi, Stored Procedure kullanımı, ilişki yönetimi vb. gibi. Veri Tabanında Connection (Bağlantı) Kavramı ve OleDbConnection Sınıfı ADO.NET mimarisinde, pek çok sınıfın veri kaynakları ile olan iletişiminde Connection (Bağlantı) nesnelerini kullanırız. Örneğin, bir veri kayağındaki tablolara ait verileri, DataSet sınıfından bir nesne örneğine taşımak istediğimizi düşünelim. Bu dataSet nesnesini dolduracak olan DataAdapter sınıfına, sahip olduğu sql sorgusunun veya komutunun işleyeceği bir hattı belirtmemiz gerekir. İşte burada devreye Connection (Bağlantı) nesnelerimiz girer. Ya da bir Command sınıfı nesnesi yardımıyla veritabanı üzerindeki bir saklı yordamı (stored procedure) çalıştırmak istediğimizi düşünelim. Bu durumda komutun çalıştırılabileceği bir hattı veri kaynağımız ile Command nesnesi arasında sağlamamız gerekir. İşte Connection (Bağlantı) nesnemizi kullanmamız için bir sebep daha. Verdiğimiz bu basit örneklerdende anlaşıldığı gibi, Connection(bağlantı) sınıfları, veri kaynağına bir hat çekerek, ADO.NET nesnelerinin bu hat yardımıyla işlemlerini gerçekleştirmelerine imkan sağlarlar. OleDbConnection baglanti=new OleDbConnection(); /* OleDbConnection nesnemiz oluşturuluyor. */ OleDbConnection sınıfı ile, bir OleDb Data Provider (veri sağlayıcısı) üzerinden, oledb destekli veri kaynaklarına erişim sağlayabiliriz. Bunu daha iyi kavramak için aşağıdaki şekle bakalım. Şekil 1 Şekil 1. OleDbConnection ile Veri Kaynaklarına Bağlantı Görüldüğü gibi bir OleDbConnection nesnesi öncelikle bir OleDb Data Provider (OleDb Veri Sağlayıcısı) ile iletişim kurar. Ardından bu veri sağlayıcı istenen veri kaynağına erişerek, gerekli hattı tesis etmiş olur. Peki bu işlemi nasıl gerçekleştireceğiz. İşte tüm Connection nesnelerinin en önemli özelliği olan ConnectionString özelliği bu noktada devreye girmektedir. Kısaca ConnectionString özelliği ile, veri kaynağı ile sağlanacak olan iletişim hattının kurulum bilgileri belirlenir. ConnectionString özelliği, bir takım anahtar-değer çiftlerinin noktalı virgül ile ayırlmasından oluşturulan string bir bilgi topluluğudur. ConnectionString özelliği içinde kullanabileceğimiz bu anahtar-değer çiftlerinin en önemlisi Provider anahtarıdır. Bu anahtara vereceğimiz değer, hangi tip oledb veri sağlayıcısını kullanmak istediğimizi belirtmektedir. Sql Sunucusundaki veritabanı için bağlantı: baglanti.ConnectionString="Provider=SQLOLEDB;Data Source=localhost;Database=veri;Integrated Security=SSPI"; Yukarıdaki kodlarda ConnectionString özelliği belirleniyor. Provider (Sağlayıcımız) SQLOLEDB. Bu bir sql sunucusuna bağlanmak istediğimizi belirtir. Data Source anahtarına localhost değerini atayarak, sunucunun yerel makinede olduğunu belirtiyoruz. Ancak buraya başka bir adreste girilebilir. Sunucunuz nerede ise oranın adresi. Database ile, bağlantı hattının açılacağı veritabanını belirliyoruz. Burada sql sunucumuzda yer alan veri isimli veritabana bağlantı hattı açıyoruz. Son olarak Integrated Security=SSPI anahtardeğer çifti sayesinde Windows Doğrulaması ile sunucuya bağlanabileceğimizi belirtiyoruz. Yani sql sunucusuna bağlanma yetkisi olan her windows kullanıcısı bu hattı tesis edebilecek. Aynı örnekte bu kez belli bir kullanıcı ile bağlanmak istediğimizi düşünelim. Bu durumda ConnectionString'imizi aşağıdaki şekilde değiştirmemiz gerekir. Bu durumda User ID ve Password anahtarlarına gerekli kullanıcı değerlerini atarız. baglanti.ConnectionString="Provider=SQLOLEDB;Data Source=localhost;Database=veri;User Id=sa;Password=CucP??80."; Access veritabanı için bağlantı: OleDbConnection baglanti=new OleDbConnection("Provider=Microsoft.Jet.OLEDB.4.0;data source=c:\\veri.mdb"); OleDbConnection baglanti=new OleDbConnection(); baglanti.ConnectionString="Provider= Microsoft.Jet.OLEDB.4.0;data source=c:\\veri.mdb"; Access 2007 için: baglanti.ConnectionString="Provider= Microsoft.ACE.OLEDB.12.0;data source=c:\\veri.accdb"); Yukarıda Provider olarak bu kez Microsoft.Jet.OLEDB.4.0 'ı seçerek, bir Access veritabanına bağlanmak istediğimizi bu Ole Db Provider'a bildirmiş olduk. Daha sonra bu veri sağlayıcı componenti, Data Source anahtarındaki değere bakarak, ilgili adresteki veritabanına bir hat çekti. Bağlatı Hattının Kullanıma Açılması ve Kapatılması: baglanti.Open(); /* Open metodu ile oluşturduğumuz iletişim hattını kullanıma açıyoruz. */ baglanti.Close(); /* Close metodu ilede oluşturulan iletişim hattını kapatıyoruz.*/ ADO.NET ile veritabanı işlemleri ADO.NET ile veritabanı işlemleri temel olarak 2 kısımda incelenebilir; • Bağlantılı Veritabanı İşlemleri (Connected Database Operations): Uygulamanın veritabanına sürekli bağlı olduğu yöntemdir. Değişiklikler veritabanına direkt olarak yansımaktadır. Gerçek zamanlı erişim sağlar. Temel nesneleri Command ve DataReader nesneleridir. Bu yöntem eski ADO versiyonunda da kullanılan yöntemdir. Bu metotta kullanıcı veritabanına bağlantı sağlar ve istediği sorguyu çalıştırır. Sorgu sonucunda geri döndürülen veriler uygulamanın ihtiyacına göre kullanılır. Veritabanına açılan bağlantı herhangi bir nedenden dolayı kesilirse kullanıcının yeni sorgular yapması mümkün değildir. Bu yüzden veri tabanı bağlantısının mümkün oılduğunca hızlı bir şekilde kullanılması gerekir. • Bağlantısız Veritabanı İşlemleri (Disconnected Database Operations): Uygulama veritabanına sürekli bağlı değildir. İşlemler veritabanının gerekli tablolarını içeren sanal bir kopyası üzerinde yapılır. Gerektiği zaman bu veriler veritabanına aktarılır. Bu aktarımlar haricinde işlemler bağlantısız bir ortamda gerçekleşmektedir. Bu yöntem ADO.NET ile birlikte kullanılmaya başlanmıştır. ADO.NET kütüphanesindeki çeşitli sınıflar yardımıyla bir veritabanındaki istenilen tablodaki kayıtların tamamı istemcinin hafızasına alınır ve veritabanına olan bağlantı kesilse bile istemci verilerle oynayabilir. Tabi veritabanı bağlantısı kesildiği anda hafızadaki verileri veritabanına güncellemek mümkün değildir.(Güncelleme için yeni bir bağlantının açılması gerekir) Bu yöntemle istemcinin hafızasında, veritabanındaki tabloların resmen bir modeli oluşturulur. DataSet isimli sınıf ile hafızadaki bu verilere sistematik bir şekilde erişmek mümkündür. Üstelik hafızadaki bu veriler içinde çeşitli kompleks işlemler bile yapılabilmektedir. Bu işlemlerden en önemlisi DataSet içindeki tablolar arasında ilişki kurmak ve gerektiğinde bu ilişkiye dayanarak çeşitli sorgular yapmaktır. C#’ta Bağlantılı(Online) Veritabanı İşlemleri (Connected Database Operations with C#) Command (Komut) Nesnesi Command nesnesi, veri kaynaklarına karşı icra edilecek komutları temsil eden ADO.NET nesnesidir. Command nesnesi de bir Provider nesnesidir ve temsil ettiği komutları icra ettirebilmesi için kurulmuş (açık) bir bağlantıya (Connection nesnesine) ihtiyacı vardır. Bu nedenledir ki açık bir bağlantıyı, Command nesnesi ile ilişkilendirmeden, onu bir komut icra ettirmek için kullanamayız.Command nesnesi ile * Direk SQL sorguları yürütebiliriz. (SELECT, INSERT, UPDATE, DELETE ve diğer DDL komutları CREATE, ALTER, ..) * Depolanmış prosedür (Stored Procedure) işletimi yaptırabiliriz. Yürüttüğümüz sorgu (veya stored procedure) sonucu dönen kayıtlara bir DataReader nesnesiyle ulaşabiliriz. Connection nesnesi sadece, uygulamamamızın veritabanı ile olan canlı ilişkisini temsil ederken, Command nesnesi bu ilişki üzerinden yürüyen her türlü alış/verişi temsil ediyor. Örnek kullanım: OleDbCommand SorguCalistir = new OleDbCommand(sorgu,baglanti); DataReader Nesnesi Command nesnesi, veri kaynağına karşı yürütülen ifadeleri temsil ediyor. Genellikle sorguları, bir veri seti döndürmek amacıyla işletiriz. ADO.NET veri sağlayıcısı, komutları icra ettiren Command nesnesinin yanında, dönen veri kümesini temsil edecek bir yapı da gerçeklemek durumundadır. Bu yapı, DataReader nesnesidir. DataReader'in başlıca özellikleri: DataReader sadece veri okumak amacıyla tasarlanmıştır ve çalışması veri kaynağıyla kurulmuş canlı bağlantıyı gerektirir. DataReader, verilerin sadece ileri yönde hareket eden akışını temsil eder. DataReader ile belli bir anda, sadece bir kayda erişebiliriz. Tüm kayıtlara erişebilmek için, veri akışının sonuna kadar hareket etmeliyiz(örneğin döngü ile). DataReader, kullandığı veri kaynağı bağlantısını, kapanana kadar kendisi için kilitler. DataReader Nesnesini Oluşturmak Daha önceden bahsettiğimiz Connection ve Command nesnelerinin aksine, DataReader nesnesini bir yapılandırıcı (constructor) metodla kendimiz oluşturamayız. DataReader, Command nesnesinin ExecuteReader() metodu ile elde edilir. Bu metod, Command nesnesinin ifade ettiği sorguyu işletir ve dönen kayıtları temsil edecek DataReader nesnesini oluşturur. Örnek kullanım: OleDbConnection baglanti = new OleDbConnection(); //Bağlantı nesnesi tanımlandı string dosyaadi; string sorgu; dosyaadi = @"..\..\..\veri.mdb"; baglanti.ConnectionString = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" + dosyaadi; //Bağlantı parametreleri tanımlandı baglanti.Open(); //Bağlantı Açıldı sorgu = string.Format("select * from Satis"); //Sorgu cümlesi tanımlandı OleDbCommand SorguCalistir = new OleDbCommand(sorgu, baglanti); //Hazırlanan sorguyu açılan “baglanti” bağlantısı üzerinden çalıştıracak olan //SoguCalistir nesnesi tanımlandı. OleDbDataReader SorguSonucu = SorguCalistir.ExecuteReader(); //Tanımlanan SorguCalistir Command nesnesinin ExecuteReader() metodu ile //geri dönecek DataReader nesnesine bağlanıyor. Veriler henüz alınmadı!! while (SorguSonucu.Read()) { listBox1.Items.Add(SorguSonucu[0].ToString()); } //Sorguya uygun olarak Read() metodu ile DataReader’a alınan verilerden ilk //sütun bilgileri (örn. SatisKodu) tek tek listBox1’e eklendi. Kaydın var //olup olmamasına göre true/ false değeri döndürecektir. //Read() metodu her seferinde bir sonraki kayda otomatik olarak //konumlanacak. Eğer getirecek kayıt kalmamışsa bu metod false değeri //verecektir; Bu da döngüden çıkmasına sebep olacaktır baglanti.Close(); //Bağlantı kapatıldı DataReader sadece tek bir kaydı hafızaya yükler. Daha önce gösterdiği kayıtlar ve daha sonra göstereceği kayıtlar hakkında en ufak bilgisi yoktur. Bu nedenle, bu nesnenin, bir veritabanı tablosunu hafızada temsil etmesini bekleyemeyiz. ADO.NET'in bu tip "offline"(bağlantısız) veri işlemleri için sunduğu DataSet adında farklı bir nesne vardır. System.Data isim uzayına bağlı DataSet nesnesine, DataAdapter nesnesi yardımı ile veritabanından kayıt çekeriz. Aslında DataAdapter nesnesi de kayıtları, kendi içinde DataReader nesnesi kullanarak almaktadır. C#’ta Bağlantısız(Offline) Veritabanı İşlemleri (Disconnected Database Operations with C#) Dataset: Sanal veritabanı da diyebiliriz. Fiziksel veritabanındaki tabloları, satırları, ilişkileri yapısında barındırabilir. Bellekte geçiçi olarak tutulur. Tamamen çevrimdışı olarak ve veri sağlayıcı türünden bağımsız olarak çalışan DataSet, içerisinde tabloları, bu tablolara ilişkin satır ve sütunları, tabloların birbirleriyle ilişkilerini hafızada saklayan bir araçtır. DataSet’i daha iyi anlayabilmeniz açısından özelliklerine değinecek olursak; Her zaman çevrimdışı olarak çalışır. Veritabanı ile direk bağlantısı yoktur. Tamamen bağımsız olarak çalışır. İçerisinde tabloları, bu tablolara ait satır ve sütunları, tablo görüntülerini ve ilişkilerini barındırır. Hızlıdır, hafızada tutulduğu için veritabanı ve ağ ortamındaki yavaşlıklar onu direk etkilemez. Veritabanı sağlayıcılarından bağımsızdır. Uyumlu DataAdapter olduğu sürece DataSet’ler bütün veritabanı sağlayıcılarıyla çalışabilir. Direk olarak veritabanı üzerinde işlem yapılmadığı için yapılan değişikliklerin geri dönüşü kolaydır. Yapılan değişikliklerin kaydını tutar. (Anahtar Kelime: RowState) DataAdapter: Dataset’le, veritabanının haberleşmesini sağlayan nesnedir. DataAdapter nesnesi ise veri sağlayıcı türlerine göre değişiklik göstermektedir. Örneğin, Access veritabanı bağlantısı için OleDbDataAdapter nesneleri, SQL Server veritabanı bağlantısı için ise SqlDataAdapter nesneleri kullanılır. Fakat kullanım şekli ve yapısı hepsinde aynıdır. DataAdapter’ın 2 temel işlevi vardır 1. Veritabanındaki istenen verileri DataSet’e aktarmak Veritabanındaki istenen verileri DataSet’e aktarmak için DataAdapter’ın Fill() metodu kullanılır. 2. DataSet’teki istenen verileri veritabanına aktarmak DataSet’teki istenen verileri veritabanına aktarmak için ise DataAdapter’ın Update() metodu çağrılır. Connection: (Daha Öncede Anlatılmıştı) Veritabanına bağlanmak için kullanılan nesne. Connection nesnesi, diğer bir ifade ile DataAdapter’ın veritabana bağlanarak verilere ulaşabilmesi ve veritabanında değişiklik yapabilmesi için gerekli fiziksel bağlantının açılmasını ve kapanmasını sağlar. Connection sınıfı yine DataSet’ten farklı olarak, DataAdapter’taki gibi veri sağlayıcı türüne bağımlı olarak çalışırlar. Örneğin, Access veritabanı bağlantısı için OleDbConnection nesnesi, SQL Server veritabanı bağlantısı için ise SqlConnection nesnesi kullanılır. Veritabanı: Verilerin fiziksel olarak tutulduğu asıl veri kaynağı (Access, SQL, Oracle vb. ile hazırlanmış veritabanı dosyaları). Aşağıdaki şekle bakarak bağlantı yapısını daha somut bir şekilde kafanızda canlandırabilirsiniz; Örnek Kullanım: OleDbConnection baglanti = new OleDbConnection(); OleDbDataAdapter da; DataTable dt = new DataTable(); OleDbCommandBuilder cb; //DataSet ds = new DataSet(); //BindingSource bs = new BindingSource(); string dosyaadi; string sqlstring; dosyaadi = @"..\..\..\veri.mdb"; con.ConnectionString = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" + dosyaadi; //baglanti.Open(); //OleDbDataAdapter nesnesi (da) bağlantıyı işlem yapmadan önce açar, //işlemini bitirdikten sonra kapatır. Bu yüzden bağlantı açamaya ve //kapamaya gerek yok.. sorgu = string.Format("select * from Satis"); //sqlstring = "select * from Satis"; da = new OleDbDataAdapter(sorgu, baglanti); //dataGridView1.Rows.Clear(); da.Fill(dt); dataGridView1.DataSource = dt; //da.Fill(ds); //dataGridView1.DataSource = ds.Tables[0]; //bs.DataSource = ds.Tables[0]; //bs.Sort = "Miktar"; //dataGridView1.DataSource = bs; cb = new OleDbCommandBuilder(da); /* CommandBuilder nesnemiz , OleDbDataAdapter nesnemiz için oluşturuluyor. CommandBuilder’a ait new yapılandırıcısı parametre olarak aldığı OleDbDataAdapter nesnesinin SelectCommand özelliğindeki sql komutuna bakarak gerekli diğer UpdateCommand,DeleteCommand ve InsertCommand komutlarını oluşturuyor. */ da.Update(dt); /*DataTable’daki veritabanına gönderiliyor. */ değişiklikler DataRow satir; satir = dt.NewRow(); satir["SatisKodu"] = textBox1.Text; satir["Tarih"] = dateTimePicker1.Text; satir["UrunAdi"] = textBox3.Text.ToString(); satir["Miktar"] = textBox4.Text.ToString(); satir["BirimFiyat"] = textBox5.Text.ToString(); dt.Rows.Add(satir); da.Update(dt); Update metodu ile, DataRow satir; int skodu; skodu = Convert.ToInt32(textBox1.Text); satir = dt.Rows[0]; dt.Rows[skodu]["Tarih"] = dateTimePicker1.Text; dt.Rows[skodu]["UrunAdi"] = textBox3.Text; dt.Rows[skodu]["Miktar"] = textBox4.Text; dt.Rows[skodu]["BirimFiyat"] = textBox5.Text; da.Update(dt); int skodu; skodu = Convert.ToInt32(textBox1.Text); dt.Rows[skodu-1].Delete(); da.Update(dt);