5 Kasım 2010

Smart Device' da SqlServerCe Database Erişimi - 3

Bu yazımızda Smart Device (Win-Ce) projelerimiz için SqlServerCe kütüphanesini kullanarak ele aldığımız Data Access sınıfımızı kullanmaya devam ediyoruz. Master-detail olarak hazırlayacağımız tablolarımıza, oluşturacağımız bir transaction ile aynı işlem içerisinde verileri kaydetmeye çalışacağız. (Buradaki işlemden kastımız oluşturacağımız bir button click event'ı dır.) Direk olarak bu makaleyi okumaya başlayan arkadaşlara önerim, öncelikle Smart Device' da SqlServerCe Database Erişimi - 1 ve Smart Device' da SqlServerCe Database Erişimi - 2 makalelerinde ele alınan konulara da göz gezdirmenizin faydalı olacağı kanısındayım.

El terminalimizin SqlServer Compact Edition db içerisinde Master-Detail olarak bulunan tablolar üzerinde veri kayıt etme, güncelleme veya silme gibi işlemlerde verilerin bütünlüğünü sağlamak, uygulamanın varlığını sürdürebilmesi açısından oldukça önemlidir diyebiliriz. Bu sebeple aynı event içerisinde gerçekleştirmek istediğimiz kayıt işlemimizi yaparken, hem transaction kullanmalı hem de veritabanı seviyesinde Foreign Key, Primary Key gibi tanımlamalarımızı da eksiksiz olarak yapmalıyız. Aşağıdaki örneklerde Primary, Foreign Key ve bunların kullanımları ile ilgili bir örnek geliştireceğiz.

Şimdi işe veritabanımızı ve tablolarımızı oluşturarak başlayalım. Burada dikkat etmemiz gereken ID int alanımızı Primary Key ve Identity(1,1) yani 1'den başlayarak otomatik 1 artan olarak tanımlıyoruz.


ID int primary key not null identity(1,1)


Alter Table SQL,

ALTER TABLE URUN

ADD CONSTRAINT FK_URUN_URUN_GRUP

FOREIGN KEY (URUN_GRUP_ID) REFERENCES URUN_GRUP(ID)


Örneğimizde master-detail olarak URUN_GRUP ve URUN tablolarını oluşturacağız. CreateDb() methodumuzu aşağıdaki gibi hazırlıyoruz.

public static void CreateDb() {

Cursor.Current = Cursors.WaitCursor;

SqlCeConnection conn_Db = null;

SqlCeCommand cmd = null;

try {

var engine = new SqlCeEngine("Data Source =" + dbPath + ";password='1234567'");

engine.CreateDatabase();

engine.Dispose();


conn_Db = new SqlCeConnection("Data Source =" + dbPath + ";password='1234567'");


conn_Db.Open();

cmd = conn_Db.CreateCommand();
cmd.CommandText = " CREATE TABLE URUN_GRUP\n" +

" (\n" +

" ID int primary key not null identity(1,1),\n" +

" ADI nvarchar(25) not null\n" +

" )";

cmd.ExecuteNonQuery();


cmd.CommandText = " CREATE TABLE URUN\n" +

" (\n" +

" ID int primary key not null identity(1,1),\n" +

" URUN_GRUP_ID int not null, \n" +

" ADI nvarchar(50) \n" +

" ) ";

cmd.ExecuteNonQuery();


cmd.CommandText = " ALTER TABLE URUN\n" +

" ADD CONSTRAINT FK_URUN_URUN_GRUP\n" +

" FOREIGN KEY (URUN_GRUP_ID) REFERENCES URUN_GRUP(ID)";

cmd.ExecuteNonQuery();

cmd.Dispose();

MessageBox.Show("Veritabanı Oluşturuldu.", "Bilgi", MessageBoxButtons.OK, MessageBoxIcon.Exclamation, MessageBoxDefaultButton.Button1);

}


catch (SqlCeException ex) {

if (cmd != null) {

cmd.Dispose();

}

ShowErrors(ex);

}

catch (Exception) {

throw;

}

finally {

Cursor.Current = Cursors.Default;

}

}



Yukarıdaki kod satırlarında dikkat edecek olursak ALTER TABLE ile URUN tablomuzun URUN_GRUP_ID alanını Foreign Key olarak tanımladık. Şimdi de oluşturduğumuz tablolara aynı event içerisinde kayıt satırları ekleyelim.


private void btnKaydet_Click(object sender, EventArgs e) {

try {


// Transaction başlatılıyor.

SqlCompactDatabase.BeginTransaction();

// Master tabloya kayıt atılıyor.

const string sqlGrup = " insert into URUN_GRUP (ADI) values(@p1) ";

MyCeParameter pGrupAdi = new MyCeParameter("@p1", "Bilgisayar",ParameterDirection.Input);


SqlCompactDatabase.ExecuteNonQuery(sqlGrup, pGrupAdi);


// Master tabloya kaydedilen Identity ID değeri elde ediliyor.

int grup_id = Convert.ToInt32(SqlCompactDatabase.ExecuteScalerText("select @@identity", null));


// Detay tabloya kayıtlar ekleniyor. Master tablodan elde edilen Grup_Id alanı da set ediliyor.

foreach (var urun in new string[] { "İşlemci", "Ana Kart", "Sabit Disk", "Solid State Disk" } ) {

string sqlUrun = " insert into URUN (URUN_GRUP_ID,ADI) values(@p1,@p2) ";

MyCeParameter pGrupId = new MyCeParameter("@p1", grup_id);

MyCeParameter pAdi = new MyCeParameter("@p2", urun);

SqlCompactDatabase.ExecuteNonQuery(sqlUrun, pGrupId, pAdi);

}


// Transaction Commit edilerek işlem tamamlanıyor.

SqlCompactDatabase.CommitTransaction();

}


catch (Exception ex) {

SqlCompactDatabase.RollBackTransaction();

MessageBox.Show(ex.Message);

}

}


Yukarıdaki C# kod satırlarında görüleceği üzere, master URUN_GRUP tablosuna kayıt ekledikten sonra bu tablonun identity ID alanı değerini @@identity ile elde etmiş olduk. select @@Identity bize tabloya en son kayıt edilen identity alanın değerini dönecektir. Elde ettiğimiz ID alanını URUN_GRUP_ID olarak, detail URUN tablosunda kullandık. URUN_GRUP_ID alanı Foreign Key tanımlandığından kayıt sırasında bir sıkıntı yaşamadık. Grup Id'si tanımlanmamış bir kayıt satırını kaydetmemiz mümkün olmayacaktı. Aksi durumda (Foreign Key bozulması
durumlarında) aşağıdaki gibi bir hata ile karşılaşılır. (A foreign key value cannot be inserted because a corresponding primary key value does not exist.)


Ayrıca şunu da belirtmeliyiz, Compact FrameworkSqlCeParameter.Direction Property her zaman için Input parametre döndürmektedir. Eğer farklı bir parameter direction verilirse InvalidOperationException hatası fırlatılacaktır.

Eğer output parametre kullanabilir olsaydık, select @@identity kullanmadan da ID değerini insert komut satırı içinde output parametre olarak döndürerek de elde etme şansımız olurdu.

Kolay gelsin.

Hiç yorum yok: