|
Geliştirdiğimiz uygulamalarda veritabanı ile ilgili işlemleri sıklıkla yapmaktayız. Veritabanına bağlanmak, verileri seçip uygulama ortamında aktarmak ve bu verileri uygulamayı kullanacak kişilerin istediğine göre sunmak, programcı olarak bizlerin en rutin işlemlerinden biridir. Tabi ki bu tip işlemleri yaparken esas alacağımız kurallardan biri de uygulamanın performanslı bir şekilde çalışmasını sağlamaktır. Bu yazımızda da veritabanından çektiğimiz verileri uygulama ortamında sakladığımız DataTable nesnesi üzerinde verileri filtreleme ve sıralama işlemlerini yapmamızı
sağlayan Find ve Select isimli iki metodu detaylı bir şekilde irdeleyeceğiz.
Dilerseniz şöyle bir senaryo ile konumuza giriş yapalım. Veritabanında ürünlerimizin bulunduğu tablodan verileri getirerek uygulama içerisinde kullanıyoruz. Kullanıcı, form üzerinde bulunan kontroller aracılığıyla aynı veri üzerinde özel kriterler
belirterek veri seçme işlemleri gerçekleştiriyor.(Sadece istenilen kriterdeki kayıtları
getir, istenilen kriterdeki verileri istenilen sırada getir... gibi) Eğer kullanıcı form üzerinde bu tip işlemleri sıklıkla yapacak ise, her seferinde veritabanına bağlantı açmak, sorgu çalıştırmak ve sorgu sonuçlarını uygulamaya aktarmak elbetteki hem uygulamanın performansını azaltacaktır, hem de veritabanında daha fazla işlem yapılacağı için sunucuda yavaşlığa sebep olacaktır. İşte böyle bir senaryoda tablodan istenilen tüm verileri alarak uygulamada (yani DataTable nesnesi içerisinde) saklamak,
daha sonra da bu veriler üzerinde filtreleme ve sıralama işlemleri yapmak uygulamamızın performansını olumlu yönde arttıracaktır.
ADO.NET içerisinde bu tip işlemleri yapmamızı sağlayan bazı yapılar mevcuttur. Bu yazımızda ise DataTable sınıfımız içerisinde bulunan bazı metotları kullanarak bu işlemleri nasıl gerçekleştireceğimizi göreceğiz. Yine DataTable nesnesi içerisindeki verileri okuyarak, bu verilerin farklı görünümlerini sunan DataView isimli bir nesne ile de bu tip işlemler yapılabilir. DataView nesnesini ilerleyen zamanlarda fırsat olursa bir makale ile sizlere sunmaya çalışacağım. Dilerseniz DataTable sınıfı içerisinde yer alan bu metotların kullanımını örnek bir uygulama ile inceleyelim. Bunun için bir Windows Application açarak aşağıdaki şekilde bir form tasarlayalım.

Şekil: Formumuzun tasarımı ve kontrollerin isimleri
Yine uygulamamızda kullanılacak verileri tutacağımız Urunler isimli tablonun tasarımını da şu şekilde gerçekleştirelim:

Şekil: MS Access'te hazırlayacağımız Urunler tablosu
İlerleyen kısımlarda daha düzgün bir şekilde ilerleyebilmek için gerekli olan nesnelerin tanımlamalarını ve Form_Load'da yapılacak işlemleri hazırlayalım.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Data.OleDb; // Veritabanı işlemleri için gerekli
isim alanını ekliyoruz.
namespace DataTable_SortFilter
{
public partial class Form1 : Form
{
// Connection, DataAdapter ve DataTable
nesnelerini field olarak tanımlıyoruz.
OleDbConnection con;
OleDbDataAdapter da;
DataTable dtUrunler;
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object
sender, EventArgs
e)
{
// Gerekli bağlantı ve sorgu cümleleri
ile nesneleri oluşturuyoruz.
// DataAdapter'ın Fill metodu ile getirilen verileri
DataTable nesnesine yüklüyoruz.
con = new OleDbConnection("Provider=Microsoft.Jet.OleDb.4.0;
Data Source=Sirket.mdb");
da = new OleDbDataAdapter("SELECT * FROM Urunler",
con);
dtUrunler = new DataTable("Urunler");
da.Fill(dtUrunler);
}
private void btnDoldur_Click(object sender, EventArgs e)
{
// btnDoldur isimli butona tıklandığında dgvUrunler
isimli gridimizi verilerle dolduruyoruz.
dgvUrunler.DataSource = dtUrunler;
}
}
} |
DataTable nesnemizi verilerle doldurduk. Şimdi yavaş yavaş sıralama ve filtreleme
işlemlerini nasıl gerçekleştirebileceğimize bakalım.
Find metodu ile Satır (DataRow) Arama
Bildiğiniz gibi, DataTable nesneleri veritabanındaki tablolara oldukça benzer nesnelerdir. Tıpkı tablolarda olduğu gibi DataTable nesnesinde tutulan sütunlardan (DataColumn) birini veya birden fazlasını, DataTable'ın PrimaryKey property'si ile primary key (birincil anahtar) olarak tanımlayabiliriz. Primary key olarak tanımlanan sütunda taşınan kayıtlar tek olmalı, yani birbirini tekrar etmemelidir. Bu aşamadan sonra artık Find metodunu kullanarak tablo içerisinde primary key sütundaki kayıtlar üzerinde arama yapılabilir. Find metodu parametre olarak object tipinden bir değer alır ki; bu değer primary key alanda taşınan değerlerden biri olmalıdır. dtUrunler adındaki
DataTable nesnemizin primary key sütunu int tipinden değer alan UrunID sütunu olacaktır.
UrunID'si 5 olan bir kaydın DataRow tipinden bilgilerine şu şekilde ulaşabiliriz.
DataRow satir = dtUrunler.Sort(5); // UrunID'si 5 olan kaydın bilgilerini DataRow
tipinden getirecektir.
Hazırlamış olduğumuz Windows uygulamasındaki btnFind isimli butonun
vazifesi txtID isimli textbox'a girilen rakamsal değerin bulunduğu
kaydın bilgilerini getirmek olacaktır. btnFind isimli butonumuzun Click event'inde
çalışacak olan metodu aşağıdaki gibi dolduralım.
private void btnFind_Click(object sender, EventArgs e)
{
// Arama işlemlerini yapabilmek için DataTable nesnesinin Primary
Key alanını
// belirlememiz gereklidir. dtUrunler nesnesinin PrimaryKey
property'si DataColumn tipinden
// bir dizi isteyeceği için öncelikli olarak bu diziyi tanımlıyoruz.
Burada unique kayıt
// saklayan herhangi bir alan tablonun Primary key'i olarak
belirlenip Find metodu ile bu
// alan üzerinde arama yapılabilir.
DataColumn[] dcPK = { dtUrunler.Columns["UrunID"] };
dtUrunler.PrimaryKey = dcPK;
// Hatalı bilgi veya olmayan bir ID girildiğinde uygulamanın
düzgün çalışması için
// işlemleri try-catch içerisinde ele alıyoruz.
try
{
int urunID = Convert.ToInt32(txtID.Text);
// Kullanıcıdan ID değerini aldık. Rows kolleksiyonunun Find metodu parametre
olarak
// verilen değeri satırlar içerisinde arar ve bulduğu satırı DataRow tipinde geriye
// döndürür. Böylece satir isimli DataRow nesnemizin
indekleyicileri ([]) aracılığıyla
// sütun isimlerini vererek kaydın bilgilerine
ulaşabiliriz.
DataRow satir = dtUrunler.Rows.Find(urunID);
string satirBilgileri = satir["UrunID"].ToString()
+ " - " + satir["Ad"].ToString() +
" - " + satir["Fiyat"].ToString()
+ " YTL";
MessageBox.Show(satirBilgileri, urunID + " ID'li
ürünün bilgileri");
}
catch (Exception ex)
{
MessageBox.Show("Satır bulunamadı!");
}
} |
Uygulamayı çalıştırdığımızda gridi doldurup varolan bir kaydın UrunID bilgisini txtID isimli textboxa yazıp butona tıklatırsak o ürün ile ilgili UrunID, Ad ve Fiyat gibi bilgileri mesaj kutusu içerisinde görebiliriz.

Şekil: Find metodu ile ID bilgisi verilen kaydın bilgilerine ulaşmak
Böylece Find metodunu kullanarak primary key sütunumuzdaki bir bilgiye göre ilgili
kaydın değerlerine nasıl ulaşabileceğimizi görmüş olduk. Find metodunun kullanımını
inceleyecek olursak bir de aşırı yüklenmiş halinin olduğunu görebiliriz. Metodun
ikinci versiyonu ise object tipinden bir dizi ister. Eğer tablomuzun primary key
alanını birden fazla sütun oluşturuyorsa, Find metodunun bu versiyonunu kullanarak
birden fazla kriter belirterek arama işlemi yapabiliriz. Örneğin dtUrunler tablomuzun
primary key alanının sadece UrunID sütunundan değilde, UrunID ve Ad sütunlarının
birleşiminden oluştuğunu varsayalım. Böyle bir durumda arama kriterini sadece UrunID
alanı üzerinden değil, hem UrunID hem de Ad alanı üzerinden verebiliriz. Aslında
Find(object key) versiyonu primary key alan üzerinden WHERE
UrunID=5 gibi bir arama yaparken, Find(object[] keys)
versiyonu ise UrunID ve Ad sütunlarının primary key olduğu bir durumda WHERE
UrunID=5 AND Ad='Çikolata-Fındıklı' şeklinde bir arama yaparak sonucu
getirir. Find metonun aşırı yüklenmiş halinin kullanımını aşağıdaki örnekte görebilirsiniz.
// UrunID ve Ad sütunlarını bir DataColumn dizisi içerisinde primary key olarak
// tanımlıyor ve dtUrunler tablomuzun PrimaryKey property'sine set ediyoruz.
DataColumn[] dcPK = { dtUrunler.Columns["UrunID"], dtUrunler.Columns["Ad"] };
dtUrunler.PrimaryKey = dcPK;
// Object tipindeki dizimizin ilk değer UrunID, ikinci değeri Ad sütunu için.
object[] urunID_Ad = {5, "Çikolata-Fındıklı"};
DataRow satir = dtUrunler.Rows.Find(urunID_Ad);
|
Select Metodu ile Filtreleme ve Sıralama İşlemleri
Find metodu primary key alan üzerinden tek bir satır ile bilgi getirir, yani bir
nevi SELECT * FROM Urunler WHERE UrunID=5 gibi bir sorgu çalıştırmamızı
sağlar. Bazı durumlarda ise sadece bir kaydın değilde belirli kriterlere uyan
kayıtların bulunmasını isteyebiliriz.(SELECT * FROM Urunler WHERE
Fiyat>1 AND Fiyat<2 gibi) Dikkat edecek olursanız
Find metodunda yapacağımız aramalar sadece primary key alanı ile kısıtlı
idi. Burada bahsettiğimiz sorguda ise sadece primary key alan üzerinden değil de,
tüm alanlarla ilgili kriterler belirtme isteğinden söz ediyoruz. Yine verdiğimiz kriterler sonucunda
getirilen kayıtların belirli bir alana göre sıralanmasını da isteyebiliriz. (SELECT
* FROM Urunler WHERE Fiyat>1 AND Fiyat<2
ORDER BY Ad gibi) Bu tip durumlarda veritabanına tekrar
SELECT sorguları göndermeden DataTable nesnesi üzerinden de sorgulama işlemleri
gerçekleştirebiliriz. DataTable sınıfı içerisinde yer alan Select
metodu bu görevi üstlenmektedir. Verilen krtier ve sıralama ifadesine göre DataTable
içerisindeki veriler üzerinde kriterlere uyan karakterleri DataRow dizisi
olarak geriye döndürür. Select metodunun versiyonlarını inceleyecek olursak;
public DataRow[] Select();
DataTable içerisindeki tüm satırları getirir.
public DataRow[] Select(string filterExpression);
DataTable içerisinden sadece filtrelenen kayıtları getirir.
public DataRow[] Select(string filterExpression, string sort);
DataTable içerisinden sadece filtrelenen kayıtları, belirtilen sıralamada
getirir.
public DataRow[] Select(string filterExpression, string sort, DataViewRowState
recordStates);
DataTable içerisinden DataRowViewState'i belirtilen kayıtlar içerisinden filtrelenen
kayıtları, belirtilen sıralamada getirir.
Metot içerisinde kullanılan parametreler ile ilgili olarak;
- filterExpression: Filtreleme ifadesi. WHERE ile kullanılacak
ifade. Örneğin; "Fiyat>1 AND Fiyat<5" gibi.
- sort: Sıralama ifadesi. ORDER BY ile kullanılacak ifade. Örneğin
Fiyat DESC gibi.
- recordStates: Bildiğiniz gibi DataTable içerisindeki veriler
üzerinde çalışma zamanında değişiklikler yapabiliyoruz. recordStates parametresi
DataTable içerisindeki kayıtların durumuna göre
seçme işleminin hangi kayıtlar arasından yapılacağını belirler. Silinmiş kayıtlar
arasından seç, değiştirilmeyen kayıtlar arasından seç gibi... DataViewRowState enum'ı (numaralandırıcı) tipinden değer alır. Bu değerler ve anlamlarını aşağıdaki listede bulabilirsiniz.
|
Added: Sadece eklenen kayıtlarda
CurrentRows: Tabloda o an varolan kayıtlarda
Deleted: Sadece silinen kayıtlarda
ModifiedCurrent: Değişen kayıtlarda (o an varolan değerleri ile
birlikte)
ModifiedOriginal: Değişen kayıtlarda (orjinal değerleri ile birlikte)
None: Hiçbir kayıtta
OriginalRows: Orjinal kayıtlarda (silinen ve değişen kayıtlar dahil)
Unchanged: Değişmeyen kayıtlarda
|
Tablo: DataViewRowState enum tipinin alabileceği değerler ve anlamları
Select metodunun örnek kullanımlarını aşağıda bulabilirsiniz.
// Tablodaki tüm kayıtları getirir.
DataRow[] satirlar = dtUrunler.Select();
// Tablodaki kayıtlarda UrunID bilgisi 5 ve 10 arasında olanları getirir.
DataRow[] satirlar = dtUrunler.Select("UrunID>5 AND UrunID<10");
// Tablodaki kayıtlarda UrunID bilgisi 5 ve 10 arasındaki kayıtları Fiyat değerleri
azalan şekilde getirir.
DataRow[] satirlar = dtUrunler.Select("UrunID>5 AND UrunID<10", "Fiyat DESC");
// Tabloda o an varolan kayıtlar içerisinde, UrunID bilgisi 5 ve 10 arasındaki kayıtları, Fiyat değerleri azalan şekilde getirir.
DataRow[] satirlar = dtUrunler.Select("UrunID>5 AND UrunID<10", "Fiyat DESC", DataViewRowState.CurrentRows); |
Yukarıdaki ifadelerin tamamından dönen sonuç DataRow dizisi şeklindedir. Dizi olarak
gelen bu kayıtları bir foreach döngüsü içerisinde uygulama ortamına aktarabiliriz.
Getirilen sonuçların label1 isimli bir Label kontrolüne yazımının
örnek kodları aşağıda yer almaktadır.
foreach (DataRow dr in satirlar)
{
label1.Text += dr["UrunID"] + " - " + dr["Ad"] + " - " + dr["Fiyat"] + "\n";
}
|
Uygulamamızın btnSelect butonuna tıklandığında txtWhereCumle
textbox'ından, cmdOrderBy
combobox'ından ve cbDesc
checkbox'ından alacağı değerlere göre filtrelenen ve sıralanan
kayıtları DataGridView kontrolüne aşağıdaki gibi doldurabiliriz.
private void btnSelect_Click(object sender, EventArgs e)
{
string whereIfade, orderByIfade;
whereIfade = txtWhereCumle.Text;
// WHERE'den sonra gelecek ifade
orderByIfade = cmbOrderBy.SelectedItem.ToString();
// ORDER BY'dan sonra gelecek ifade
if (cbDesc.Checked)
orderByIfade += " DESC"; // Tersten
sıralama yapılacaksa ifademize DESC ekliyoruz
DataRow[] satirlar = dtUrunler.Select(whereIfade, orderByIfade);
// Seçilen satırlar dtUrunler isimli tabloya ait olduğu için
başka yapıya sahip
// bir DataTable nesnesine yüklenemez! Buradaki sorunu aşabilmek
için yeni
// bir DataTable nesnesini dtUrunler isimli tablonun Copy metodu
ile oluşturuyoruz.
// Yani dtGecici isimli tablomuz dtUrunler tablosu ile aynı
yapıya sahip oluyor.
// Fakat bize sadece o an seçilen veriler gerekli(satirlar dizisi).
Bu nedenle de
// dtGecici'deki row'ları Clear metodu ile siliyoruz. Select
metodunun kullanımında
// benzer durumlarda sıkıntı çıkabilmektedir. Burada ele almadığımız
DataView nesnesi
// bu problemleri çözebilecek şekilde dizayn edilmiştir.
DataTable dtGecici = dtUrunler.Copy();
dtGecici.Clear();
foreach (DataRow dr in satirlar)
{
// satirlar nesnesindeki row'lar hala
dtUrunler tablosuna ait olduğu için
// ImportRow metodu ile satırları kopyalıyoruz
dtGecici.ImportRow(dr);
}
dgvUrunler.DataSource = dtGecici; // Verileri
gride yüklüyoruz.
} |
txtWhereCumle isimli textbox'a arama kriterlerimizi, cmbOrderBy combobox'ına sıralanacak
alanın girişini yaparak, sıralamayı tersten yapmak istiyorsak cbDesc checkbox'ını
seçerek istenilen verileri grid içerisine doldurabiliriz.

Şekil: Filtreleme ve Sıralama işlemlerinin yapılması ve sonuçların elde edilmesi
Bu yazımızda DataTable üzerinde filtreleme ve sıralama işlemlerini gerçekleştirmemizi
sağlayan Find ve Select metotlarını derinlemesine incelemeye çalıştık. Veritabanından getirilen
aynı veriler üzerinde sıklıkla sorgulama yapacağımız durumlarda (özellikle raporlama, listeleme vb. işlemlerde) veritabanına sürekli bağlanarak aynı veriler üzerinde sorgu çalıştırmak
performans ve zaman açısından olumsuz sonuçlar doğurabilir. Bu tip durumlarda DataTable
sınıfı içerisinde yer alan Select metodu ile birden fazla satır üzerinde seçme işlemleri,
yine DataTable içerisinde bulunanan Rows kolleksiyonuna ait Find metodu ile de tek
kaydı seçme işlemlerini gerçekleştirebiliriz. Bu işlemleri yaparken sorgulamalar
veritabanı üzerinde değil de, DataTable nesnemiz üzerinde gerçekleşeceği için bilgisayarın
belleğinde tutulan bir veri üzerinde gerçekleşen bu işlemler daha hızlı olacaktır.
Bu noktada bu işlemler yapılırken veritabanı üzerinde yapılacak değişikliklerin uygulamaya yansımayacağını da
unutmamamız gerekir.
Bir başka makalede görüşmek dileğiyle...
Uğur UMUTLUOĞLU
www.umutluoglu.com
www.nedirtv.com
|