Hızlı Konu Açma

Hızlı Konu Açmak için tıklayınız.

Son Mesajlar

Konulardaki Son Mesajlar

Reklam

Forumda Reklam Vermek İçin Bize Ulaşın

Binary Serialization ile Verilerin Saklanması ve DataTable Kullanımı

YaSa22

Fahri Üye
Fahri Üye
Katılım
12 Temmuz 2014
Mesajlar
2,293
Tepkime puanı
2
Puanları
0
Konum
GTA
erileştirme (serialization) işlemi, son durumlarını korumak istediğimiz nesnelerin, hiçbir veri kaybına uğramadan, geçici olarak hafızada veya kalıcı olarak bir dosyada saklanmasıdır. Bu dosya tipi XML veya binary olabilir. Bunlar her ortamdan kolayca erişilebilen basit dosya tipleridir.

Uygulamalarımızdan çok büyük miktarlardaki verilere ulaşabiliriz; bunları uygulamadan bağımsız olarak başka yerlere transfer edip diğer kullanıcılarla paylaşabiliriz. Dosyada belli bir formatla kaydedilmiş verilerin okunarak alınması ve nesnedeki haline döndürme işlemini de ters serileştirme (deserialization) olarak tanımlayabiliriz. Başka bir deyişle, bir akışın (stream) tekrar nesne modeline çevrilmesi işidir. Sonuç olarak, bu dönüşümlerle beraber nesnelerin kullanım süreleri, uygulamanın kullanım süresine bağımlı kalmaz. Serileştirme işlemleri için .NET Framework iki metod kullanmamıza olanak vermektedir:


XML ve SOAP serileştirme
Binary serileştirmeSerileştirme için kullanılan dosya formatının XML olması, bir çok avantaj getirir. Bu format çok yaygın, esnek, kullanışlı ve basittir. Açık bir standart olduğundan ve birçok uygulama tarafından rahatlıkla okunabildiğinden veri paylaşımı oldukça hızlı sağlanabilmektedir. XML dosya formatı, tüm işletim sistemleri üzerinde çalıştırılabilir ve internet üzerinden veri taşıması için kullanılabilir. Veritabanı uygulamalarında, xml dosyasını serileştirme veya ters serileştirme işlemine tabi tutarken, verileri hemen dataset içine de alabiliriz. Bunun bir sakıncası, metin temelli olduğu için, başka kişiler tarafından kolayca okunabilmesi veya yetkisiz kimselerin üzerinde değişiklikler yapabilmesidir.

XML’in getirdiği bütün avantajlara rağmen, güvenlik açısından binary formatı kullanmak daha yararlıdır. Bu format ikili kodlama temelli olduğundan, dosyanın içi okunabilecek bir yapıda değildir. Ayrıca, binary serileştirme metodu hızlı taşıma, daha yüksek oranlarda bilgi depolama ve az yer kaplayan dosya avantajlarını sunmaktadır. Farklı uygulamalar arasında nesne modelleri rahatlıkla transfer edilebilmektedir. İstediğimiz bir nesne modelini kendi diskimiz üzerinde bir dosyada saklayabileceğimiz gibi ağ üzerindeki başka bir bilgisayara da yollayabiliriz. Bu yüzden, geliştireceğimiz örnek projede binary formatı kullanacağız.

Geliştireceğimiz proje, öncelikle bir işletmenin cari hesaplar özetini (muhasebedeki mizanlar gibi) binary formatlı bir dosyada saklıyor. Kullanmak istediğimiz bu özet liste;



  • Cari hesap kodu,
  • Firma Adı,
  • Borç,
  • Alacak,
  • Döviz birimi

başlıkları adı altında bize verileri gösterecektir. Bu projede oluşturulan dosya cari.dat olarak kaydedilmiştir. Dosyadaki verilerimize istediğimiz zaman erişebilecek, kayıt ekleme, değiştirme, silme, tekrar kaydetme işlemlerini yapabileceğiz. Burada binary serialization ile deserialization işlemleri uygulanacak ve dosyadan okunan veriler DataGridView ile gösterilecektir. Böylece kendimize ait basit bir veritabanı yaratabilecek ve kullanabileceğiz. Uygulamanın görüntüsü aşağıdaki gibi olacaktır:

Projeye basit bir cari sınıfı tanımlamakla işe başlayalım. Bu sınıfın serileştirilebilir tipte olmasına özen gösterelim ve Serializable özelliğini ekleyelim. Cari hesaplar özeti tablosundaki alanlar sınıf içinde bir özellik olarak tutulur.

using System;
using System.Collections;
using System.Runtime.Serialization;

// Serileştirme için kullanılacak sınıf
[Serializable]
class Cari: ISerializable
{
// Cari sınıfı üyelerini tanımla
private string _kodu = "";
private string _firma = "";
private decimal _borc = 0;
private decimal _alacak = 0;
private string _doviz = "";

// Cari sınıfı özellikleri
public string Kodu
{
get { return _kodu; }
set { _kodu = value; }
}

public string Firma
{
get { return _firma; }
set { _firma = value; }
}

public decimal Borc
{
get { return _borc; }
set { _borc = value; }
}

public decimal Alacak
{
get { return _alacak; }
set { _alacak = value; }
}

public string Dovizi
{
get { return _doviz; }
set { _doviz = value; }
}

// Kurucu metod
public Cari(string kodu,
string firma,
decimal borc,
decimal alacak,
string doviz)
{
Kodu = kodu;
Firma = firma;
Borc = borc;
Alacak = alacak;
Dovizi = doviz;
}
}



Kendi serileştirme işlemlerimizi kontrol edebilmek için ISerializable interface uygulayalım. Bu, hangi alanların yazılıp yazılmayacağı veya hangi başlıklarla görüntüleneceği gibi işleri yapmamıza olanak verir. Burada serileştirme sırasında, GetObjectData metodu çağrılacaktır. Serileştirme esnasında, değişkenler anahtar ve değer çiftleri halinde SerializationInfo parametresine aktarılır. Sınıfımıza serileştirme metodumuzu ekleyelim:
// Serileştirme metodu
public void GetObjectData(SerializationInfo info, StreamingContext context)
{
info.AddValue("C/H Kodu", _kodu);
info.AddValue("Firma Adı", _firma);
info.AddValue("Borç", _borc);
info.AddValue("Alacak", _alacak);
info.AddValue("Döviz", _doviz);
}



Serileştirilen nesneler, ters serileştirme zamanında SerializationInfo parametresinden alınırlar. Burada, GetValue metodu kullanılabilir. Ama, biz kullandığımız veri tiplerine göre GetString, GetDecimal kullanacağız. Şimdi de sınıfımıza ters-serileştirme metodumuzu ekleyelim:
// Ters serileştirme kurucu metodu
public Cari(SerializationInfo info, StreamingContext context)
{
Kodu = info.GetString("C/H Kodu");
Firma = info.GetString("Firma Adı");
Borc = info.GetDecimal("Borç");
Alacak = info.GetDecimal("Alacak");
Dovizi = info.GetString("Döviz");
}


İkinci sınıfımızı da tanımlayalım. Cari sınıfı içinden oluşturduğumuz nesneleri, binary dosyaya yazdırmak için bunları dinamik bir dizi nesnesi içine ekleyelim. Kaç adet verimiz olacağını bilmediğimizden burada ArrayList nesnesini tanımlamak uygun olacaktır. Bunun için using System.Collections bildirimini ekliyoruz. ArrayList nesnesiyle, cari hesaplar özet listemizle ilgili olarak string ve decimal veri tiplerimizi yerleştirebiliyoruz. Bu diziyi serileştirip diske kaydetmek yeterli olacaktır. CariArrayList adlı bu sınıfa da Serializable özelliğini ekleyelim. Cari sınıfından türetilen bir nesne, aldığı özellik değerleriyle, cari hesaplar özetindeki bir satırı temsil eder. Daha sonra, bu nesne ArrayList türünden olan CariArrayList koleksiyonuna eklenir.

[Serializable]
class CariArrayList: ArrayList
{
// ArrayList kapasitesini, gerçek eleman sayısıyla eşitler.
public void setCapacity(ArrayList myAL)
{
// Depolanabilecek eleman sayısı, gerçek eleman sayısından
// büyük mü?
if (myAL.Capacity > myAL.Count)
{
// Kapasitesiyi eleman sayısıyla eşitler.
myAL.TrimToSize();
}
}
}


Bu sınıfta bir metodumuz bulunuyor. ArrayList içindeki depolanabilecek eleman sayısı kapasitesi ile gerçek durum arasında her zaman bir fark olmaktadır. Bunu minimize etmek için ArrayList içinde yeralan elemanların sayısını ayarlayan setCapacity adlı metodumuzu kullanacağız. Bununla, dizi içindeki gerçek eleman sayısıyla kapasiteyi eşit hale getireceğiz.

Sınıflarımız tanımlandıktan sonra, şimdi formumuzu tasarlamaya başlayalım. Bir adet DataGridView, beş adet button ve bir adet label kontrollerini formun üzerine yerleştirelim. Serileştirme için System.Runtime.Serialization ve BinaryFormatter erişmek için de System.Runtime.Serialization.Formatters.Binary isim uzaylarını ekleyelim. Metodların dışında dosyamızın adını, sınıfımızı ve bir DataTable tanımlayalım. Proje kodumuz aşağıdaki gibi devam etmektedir.

private void Form1_Load(object sender, EventArgs e)
{
// Binary dosyanın yeraldığı dizin ve ismi verilir.
sFileName = "cari.dat";

// Verileri DataGridView de göstermek için DataTable kullanıyoruz.
// Bellekte kullanılacak DataTable nesnesini oluştur.
myDataTable = new DataTable("cari");

// Columns koleksiyonuna tablo alanlarını ekle.
DataColumn cid = myDataTable.Columns.Add("C/H Kodu", typeof(string));
cid.AllowDBNull = false;
cid.Unique = true;
// Tablo için primary key belirle.
myDataTable.PrimaryKey = new DataColumn[] { cid };

// Diğer alanları da adları ve veri türleriyle beraber ekleyelim.
myDataTable.Columns.Add("Firma Adı", typeof(string));
myDataTable.Columns.Add("Borç", typeof(decimal));
myDataTable.Columns.Add("Alacak", typeof(decimal));
myDataTable.Columns.Add("Döviz", typeof(string));

// dataGridView1 konrolüne myDataTable nesnesini bağla.
dataGridView1.DataSource = myDataTable;

// DataGridView üzerindeki Borç ve Alacak sütunlarını formatla.
// Alignment özelliği ile sağa hizalı yazdır.
dataGridView1.Columns["Borç"].DefaultCellStyle.Alignment =
DataGridViewContentAlignment.MiddleRight;
dataGridView1.Columns["Borç"].DefaultCellStyle.Format = "N";
dataGridView1.Columns["Alacak"].DefaultCellStyle.Alignment =
DataGridViewContentAlignment.MiddleRight;
dataGridView1.Columns["Alacak"].DefaultCellStyle.Format = "N";

// Sütunların genişliklerini ayarla.
dataGridView1.Columns["C/H Kodu"].Width = 75;
dataGridView1.Columns["Firma Adı"].Width = 164;
dataGridView1.Columns["Borç"].Width = 81;
dataGridView1.Columns["Alacak"].Width = 81;
dataGridView1.Columns["Döviz"].Width = 50;

// CariArrayList sınıfından, CariListe nesnesi örneğini çıkarıyoruz.
CariListe = new CariArrayList();

// Dosyanın var olup olmadığı kontrol ediliyor.
if (File.Exists(sFileName))
{
// İçinde verilerimizin yeraldığı binary dosyayı açmak için
// FileStream kullanıyoruz.
// Ters serileştirmede kullanılacak.
FileStream fs = new FileStream(sFileName, FileMode.Open);

try
{
// Ters serileştirmede kullanmak için BinaryFormatter tanımla.
BinaryFormatter binformatter = new BinaryFormatter();

// FileStream akışından gelen verilere ters serileştirme
// uygulandıktan sonra CariArrayList sınıfı türüne çevriliyor.
CariListe = (CariArrayList)binformatter.Deserialize(fs);
}
catch (ArgumentNullException)
{
MessageBox.Show("Veri dosyasına erişilemiyor.");
}
catch (SerializationException)
{
MessageBox.Show("Uygulama serileştirme işlemini yaparken hata oluştu.");
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
finally
{
fs.Close(); // FileStream kapat.
}

// CariListe koleksiyonundaki elemanlar için döngu kuruluyor.
foreach (Cari cari in CariListe)
{
// CariArrayList koleksiyonundaki, Cari türündeki nesneler
// tablomuza satırlar halinde ekleniyor.
myDataTable.Rows.Add(new object[] {cari.Kodu, cari.Firma, cari.Borc, cari.Alacak, cari.Dovizi});
}

// CariListe koleksiyonundaki elemanları sil.
CariListe.Clear();
}

// CariListe koleksiyonundaki eleman sayısını yazdır.
lblStatus.Text = "Satır sayısı: " + CariListe.Count.ToString();
}


Şimdi yeni bir kayıt girmek istersek veya bir kaydı düzeltmek istersek, bilgi girişi için kullanacağımız formu tasarlayalım. Projemize yeni bir Windows Forms ekleyelim ve adını CariFis olarak verelim. Formumuza üç adet TextBox, iki adet ComboBox, iki adet Button ve beş adet Label kontrollerini yerleştirelim. Cari hesap kodunu gireceğimiz TextBox adını txbKodu, firma adını gireceğimiz TextBox bileşeninin adını txbFirma, tutar gireceğimiz TextBox için txbTutar olarak verelim. Cari hesabın tipini cbxCariTipi kontrolünden borç veya alacak seçelim. Hesabın para birimi veya dövizi, cbxDoviz den seçilir. Vazgeç düğmesinin DialogResult değerini "Cancel" girelim.

Tamam düğmesine çift tıklayalım ve aşağıdaki kodları yazalım:

// Ana formdan çağrıldığı zaman,
// Tutar adlı değişkenden decimal veri türünde sayı okunacak.
public decimal Tutar;

private void btnOk_Click(object sender, EventArgs e)
{
// Kayıt bilgilerinin eksiksiz girişini sağla.
if ((txbKodu.Text == "") ||
(txbFirma.Text == "") ||
(txbTutar.Text == ""))
{
MessageBox.Show("Tüm alanların doldurulması zorunludur.", "Dikkat",
MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
}
else
{
try
{
// Girilen string ifadeden decimal türü oluştur.
Tutar = decimal.Parse(txbTutar.Text);
// Tutar negatifse uyarı mesajı ver.
if (Tutar < 0)
{
MessageBox.Show("Negatif sayı girdiniz.", "Dikkat",
MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
txbTutar.Focus();
return;
}//end if
}
// Sayısal olmayan karakterler varsa (virgül ve nokta hariç),
// Parse yöntemi bir istisna ortaya çıkarır.
catch (FormatException)
{
MessageBox.Show("Girdiğiniz tutar geçersiz." +
"\nLütfen tekrar deneyin.");
txbTutar.Focus();
return;
}//end try-catch

DialogResult = DialogResult.OK;
}//end if
}


Yeni düğmesine basarsak CariFis formumuz karşımıza gelir. Yeni bir kaydın girildiğini, yukarıdaki resme benzer şekilde varsayarsak, kodumuz şu şekli alacaktır:

private void btnNew_Click(object sender, EventArgs e)
{
// CariFis form nesnesini oluştur.
CariFis frmCariFis = new CariFis();

// ShowDialog metodunu çağırıyoruz.
if (frmCariFis.ShowDialog() == DialogResult.OK)
{
string sCHKodu = frmCariFis.txbKodu.Text;
// DataTable içinde satır var mı?
if (myDataTable.Rows.Count > 0)
{
// Kaydetmek istenilen yeni cari kodu, tabloda yer alıyor mu?
// Yoksa, tabloya yeni satır ekle.
if (!myDataTable.Rows.Contains(sCHKodu))
{
addDataRow(sCHKodu,
frmCariFis.txbFirma.Text,
frmCariFis.cbxCariTipi.SelectedIndex,
frmCariFis.Tutar,
frmCariFis.cbxDoviz.Text);
}
else
{
MessageBox.Show("’" + sCHKodu + "’ cari hesap kodu önceden kaydedilmiş.");
}
}
// DataTable henüz boş satırı ekle.
else
{
addDataRow(sCHKodu,
frmCariFis.txbFirma.Text,
frmCariFis.cbxCariTipi.SelectedIndex,
frmCariFis.Tutar,
frmCariFis.cbxDoviz.Text);
}//end rows.count
}//end if ShowDialog
// frmCariFis nesnesini serbest bırak.
frmCariFis.Dispose();
}


Tabloya satır ekleyen addDataRow adlı metodumuzu yazalım. Cari hesap kodunu, firma adını, cari hesap tipini (borç veya alacak), tutar ve döviz birimini parametre olarak giriyoruz.

private void addDataRow(string sCHKodu, string sFirma, int iBATipi,
decimal dTutar, string sDoviz)
{
// Yeni bir DataRow nesnesi oluştur.
DataRow row = myDataTable.NewRow();

row["C/H Kodu"] = sCHKodu;
row["Firma Adı"] = sFirma;
switch (iBATipi)
{
// Borç girişi
case 0:
row["Borç"] = dTutar;
row["Alacak"] = 0;
break;
// Alacak girişi
case 1:
row["Borç"] = 0;
row["Alacak"] = dTutar;
break;
}
row["Döviz"] = sDoviz;
// Tabloya satırı ekle.
myDataTable.Rows.Add(row);
}


Tablo üzerinde yaptığımız değişiklikleri kalıcı olarak dosyamızda saklamak için Kaydet düğmesine basalım.

private void btnSave_Click(object sender, EventArgs e)
{
if (myDataTable.Rows.Count > 0)
{
// Kayıt için Serialize metodunu çağır.
BinSerialize();
}
}


BinSerialize() metodu, tabloya girilen kayıtları binary biçiminde serileştirir.

public void BinSerialize()
{
// FileStream kullanarak yazdırma için dosya açılıyor
// veya oluşturuluyor.
FileStream fs = new FileStream(sFileName, FileMode.OpenOrCreate);

// Serileştirilecek veri için BinaryFormatter nesnesi oluştur.
BinaryFormatter formatter = new BinaryFormatter();
try
{
for (int i = 0; i < myDataTable.Rows.Count; i++)
{
// DataRow nesnesi oluştur.
DataRow row = myDataTable.Rows;

// Silinmemiş satırları seç.
if (row.RowState != DataRowState.Deleted)
{
// Tablodaki satırları, Cari sınıfı türüne çevriliyor ve
// CariListe koleksiyonuna ekleniyor.
CariListe.Add(new Cari(row["C/H Kodu"].ToString(),
row["Firma Adı"].ToString(),
Convert.ToDecimal(row["Borç"]),
Convert.ToDecimal(row["Alacak"]),
row["Döviz"].ToString()));
}//end if
}//end for

// CariListe kapasitesini düşürmek için setCapacity metodunu çağır.
CariListe.setCapacity(CariListe);

// CariListe nesne tipi örneklerini dosyaya aktar.
formatter.Serialize(fs, CariListe);
}
catch (ArgumentNullException)
{
MessageBox.Show("Veri dosyasına erişilemiyor.");
}
catch (SerializationException)
{
MessageBox.Show("Uygulama serileştirme işlemini yaparken hata oluştu.");
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
finally
{
fs.Close(); // FileStream kapat.
}
}





Buraya kadar sadece serileştirilmiş verilerin, DataGridView kontrolüyle gösterilmesini ve kayıt eklemeyi gördük. Şimdi kayıt güncellemeyi de inceleyim. Değiştir düğmesine çift tıklayalalım ve aşağıdaki kodları yazalım:

private void btnEdit_Click(object sender, EventArgs e)
{
if (myDataTable.Rows.Count > 0)
{
// Seçmiş olduğumuz satırın indeksi
int index = dataGridView1.CurrentRow.Index;
// Seçilen cari hesabın kodunu sCHKodu değişkeninde saklıyoruz.
string sCHKodu = myDataTable.Rows[index]["C/H Kodu"].ToString();

// CariFis form nesnesini oluştur.
CariFis frmCariFis = new CariFis();

// Seçmiş olduğumuz kaydın frmCariFis üzerinde gösterimi:
// Cari kodu ve firma adını TextBox kontrollerinin
// Text değerlerine atayalım.
frmCariFis.Text = "Kayıt değiştirme";
frmCariFis.txbKodu.Text = sCHKodu;
frmCariFis.txbFirma.Text = myDataTable.Rows[index]["Firma Adı"].ToString();
// Seçmiş olduğumuz kaydın borç veya alacak tipine göre
// cbxCariTipi adlı ComboBox kontrolünün ayarlanması ve
// tuttarın yazılması.
if (myDataTable.Rows[index]["Borç"].ToString() != "0")
{
frmCariFis.cbxCariTipi.SelectedIndex = 0;
frmCariFis.txbTutar.Text = myDataTable.Rows[index]["Borç"].ToString();
}
else
{
frmCariFis.cbxCariTipi.SelectedIndex = 1;
frmCariFis.txbTutar.Text = myDataTable.Rows[index]["Alacak"].ToString();
}
// Seçmiş olduğumuz kaydın döviz cinsinin verilmesi
frmCariFis.cbxDoviz.SelectedIndex =
frmCariFis.cbxDoviz.FindString(myDataTable.Rows[index]["Döviz"].ToString());

// ShowDialog metodunu çağırıyoruz.
if (frmCariFis.ShowDialog() == DialogResult.OK)
{
// CariFis formundaki cari kodu sCHKodu_New değişkenine ata.
string sCHKodu_New = frmCariFis.txbKodu.Text;

// Kaydın cari kodu değiştirilmiş mi?
if (sCHKodu != sCHKodu_New)
{
// Değiştirilmek istenen cari kodu, tabloda daha önce
// yer alıyor mu? Yoksa, tablodaki satırı güncelle.
if (!myDataTable.Rows.Contains(sCHKodu_New))
{
editDataRow(index,
sCHKodu_New,
frmCariFis.txbFirma.Text,
frmCariFis.cbxCariTipi.SelectedIndex,
frmCariFis.Tutar,
frmCariFis.cbxDoviz.Text);
}
else
{
MessageBox.Show("’" + sCHKodu + "’ cari hesap kodu önceden kaydedilmiş.", "Dikkat",
MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
}
}
else
{
// Tablodaki satırı güncelle.
editDataRow(index,
sCHKodu,
frmCariFis.txbFirma.Text,
frmCariFis.cbxCariTipi.SelectedIndex,
frmCariFis.Tutar,
frmCariFis.cbxDoviz.Text);
}
}//end if ShowDialog
// frmCariFis nesnesini serbest bırak.
frmCariFis.Dispose();
}//end if rows.count
}


Kayıt silme işini şu şekilde yapabiliriz: DataGridView üstünde silmek istediğimiz bir satırı seçelim. Daha sonra, Sil düğmesine basalım. Aşağıdaki kod parçasına dikkat edilirse, satır tablomuzdan fiziksel olarak silinmez. Kaydımız, sadece silinecek olarak işaretlenir. Tamamen silmek için Kaydet düğmesine basmamız yeterli olacaktır.

private void btnDelete_Click(object sender, EventArgs e)
{
if (myDataTable.Rows.Count > 0)
{
// Silme isteği için kullanıcıyı uyar.
if (MessageBox.Show("Silmek istediğinizden emin misiniz?", "Silme",
MessageBoxButtons.YesNoCancel, MessageBoxIcon.Warning,
MessageBoxDefaultButton.Button2)
== DialogResult.Yes)
{
// Tablodaki kaydı silinecek olarak işaretle.
myDataTable.Rows[dataGridView1.CurrentRow.Index].Delete();
}//end if
}
}
 

Users Who Are Viewing This Konu (Users: 0, Guests: 1)

Üst