Ekim ayı blog kayıtları
CSS Transparent BackColor

CSS tarafından herhangi bir nesnenin arka plan rengini transparan hale getirmek için aşağıdaki kodu kullanabilirsiniz :



filter:Alpha(opacity=50);

Not : 50 değeri geçiş derecesini belirler.

MARS (Multiple Active Results Sets)

            Makalemizin konusu olan MARS (Multiple Active Results Sets) ADO.NET 2.0 ile gelen yeni ve veritabanı konusunda önemli bir yapıdır. MARS (Multiple Active Results Sets) kısaca tek bağlantı (connection) üzerinden birden fazla sorguyu (command) işleyebilen ve/veya geriye sonuç döndürebilen bir yapıdır.

 

         MARS yapısını daha iyi anlayabilmek için öncelikle ADO.NET 1.0 ve ADO.NET 1.1 içerisindeki connection command nesnelerinin işleyişini ve sorgu (query) işleme yapısını incelemek gereklidir.ADO.NET 1.1 ve öncesinde database ile ilgili bir işlem yapmak istediğimizde her sorgumuz için veritabanına bir bağlantı açmamız ve bu bağlantı üzerinden sorgumuzu işlememiz gerekiyordu ya da aynı bağlantıyı her sorgu için aktif hale getirip tekrar kapatmamız (close) gerekiyordu. Mesela bir console uygulaması yazdığımızı düşünelim. Bu uygulamada Northwind database ? i gibi employees ve orders isminde iki tablodan bir rapor almak istediğimizi varsayalım.

 

EmployeeID             firstName                 lastName

                1                     Nancy                    Davolio

 

Bu bilginin altında da orders tablosundan bu çalışana bağlı Order ları listelemek isteyelim. Orders tablosundan OrderID alanını listeleyelim. Bu raporu ADO.NET 1.1 ve öncesinde yapabilmek için veritabanı ile birden fazla sayıda bağlantı kurmamız gerekirdi. İlk önce employees tablosu için bir command çalışmalı :

 

         Select EmployeeID,firstName,lastName from employees

 

Sorgusunu çalıştırdıktan sonra buna bağlı başka bir sorgu daha çalıştırmalıyız:

 

         Select OrderID from Orders Where EmployeeID = @EmpID

 

Bu sorgu sonuçlarını da ekrana detay bilgi gibi listelemek istediğimizi varsayalım:

Bu durumda iki ayrı bağlantı yardımı ile raporumuzu üretebiliyorduk.Fakat ADO.NET 2.0 ile artık iki ayrı datareader nesnemizi tek connection üzerinden koşturabileceğiz.Yine iki sorgu çalışacak ama tek fark bu iki sorgu tek connection nesnesi üzerinden eş zamanlı olarak çalışacak.

 

 

Örnek olarak bir Windows uygulaması yapalım ve Northwind database ? indeki Products, Categories, Employees, Orders, Shippers tablolarını okuyup formumuzdaki 5 adet listbox kontrolünde listeyelim. Bu işlemide tek baglantı  üzerinden yapmaya çalışalım :    

 

SqlConnection cn;

 

private void btnSorgu_Click(object sender, System.EventArgs e)

{

      cn = new SqlConnection();

      cn.ConnectionString = "data source=.;initial

catalog=Northwind;trusted_connection=SSPI;";

 

      SqlCommand cmd1 = new SqlCommand();

      cmd1.Connection=cn;

      cmd1.CommandText = "Select * From Products";

 

      SqlCommand cmd2 = new SqlCommand();

      cmd2.Connection=cn;

      cmd2.CommandText = "Select * From Categories";

                 

      SqlCommand cmd3 = new SqlCommand();

      cmd3.Connection=cn;

      cmd3.CommandText = "Select * From Employees";

                 

      SqlCommand cmd4 = new SqlCommand();

      cmd4.Connection=cn;

      cmd4.CommandText = "Select * From Orders";

                 

      SqlCommand cmd5 = new SqlCommand();

      cmd5.Connection=cn;

      cmd5.CommandText = "Select * From Shippers";

 

      try

      {

            cn.Open();

            SqlDataReader dr1 = cmd1.ExecuteReader();

            SqlDataReader dr2 = cmd2.ExecuteReader();

            SqlDataReader dr3 = cmd3.ExecuteReader();

            SqlDataReader dr4 = cmd4.ExecuteReader();

            SqlDataReader dr5 = cmd5.ExecuteReader();

            lstProducts.Items.Clear();

            while (dr1.Read())

            {

                  lstProducts.Items.Add(dr1["ProductName"].ToString());

            }

 

            lstCategories.Items.Clear();

            while (dr2.Read())

            {

                  lstCategories.Items.Add(dr2["CategoryName"].ToString());

            }

 

            lstEmployees.Items.Clear();

            while (dr3.Read())

            {

lstEmployees.Items.Add(dr3["firstName"].ToString()+" "+dr3["lastName"].ToString());

            }

 

            lstOrders.Items.Clear();

            while (dr4.Read())

            {

lstOrders.Items.Add(dr4["OrderID"].ToString()+" "+dr4["OrderDate"].ToString());

            }

 

            lstShippers.Items.Clear();

            while (dr5.Read())

            {

                  lstShippers.Items.Add(dr5["companyName"].ToString());

            }

      }

      catch (Exception ex)

      {

            MessageBox.Show(ex.Message,"Error",MessageBoxButtons.OK,MessageBoxIcon.Error);}

      finally

      {

            cn.Close();

      }          

}

 

 

Bu örnek programı çalıştırdığımızda SQL Server tarafından istemci uygulamaya bir istisna (Exception) gönderilecektir. Hata mesajı :

 

?There is already an open DataReader associated with this Connection which must be closed first.?

 

Çünkü sqldatareader nesnesi kendi komutunun çalışması bitene kadar bağlantının açık kalmasını zorunlu koşar ve aynı bağlantıyı baksa bir nesnenin kullanmasına izin vermez.

 

 

Bu programdaki hatayı çözebilmek için ya tek  connection nesnemiz olan cn ? i her sefer açıp kapatmamız gerekir ya da her sqldataReader nesnemiz için ayrı bir connection nesnesi oluşturmamız gerekir.Bu her iki çözümde de karşımıza bir hata mesajı gelmeyecek fakat bu tip kullanımlar bizim sistem kaynaklarımızı fazlasıyla tüketecektir.Şu anda verdiğimiz örnekte bu kaynak tüketimini tam anlamıyla hissedemeyiz fakat öyle bir program düşünün ki kayıt sayısı 5,000,000 dan fazla iki adet tabloyu sorgulamamız gerekmekte. Böyle bir durumda yaratacağımız her bağlantı nesnesi veritabanımızda ayrı bir bağlantı açacak ve sistem kaynaklarını fazlasıyla tüketmeye başlayacaklardır. Ayrıca bunlar eş zamanlı ilerleyemeyeceği için ilk gönderilen komut işlemini bitirmeden diğerine geçilmeyecek tüm komutlar teker teker birbirinin bitmesini bekleyecek ve biz bilgisayarın başında epey zaman harcamak zorunda kalacağız.

 

Fakat artık ADO.NET 2.0 bu ve bunun gibi ihtiyaçlar doğrultusunda yeni bir yapı getirmiştir.Bu yapının ismi MARS (Multiple Active Results Sets) (Asenkron komut yürütme de diyebiliriz). MARS açık bir bağlantı üzerinden birden fazla sql komutunun eş zamanlı olarak çalıştırılmasını sağlar. MARS yapısını kullanabilmemiz için veritabanı sistemimizin bu yapıyı destekliyor olması gerekmektedir.

 

Şimdide MARS yapısına dayanan, ADO.NET 2.0 ile SQL Server 2005 üzerinde çalışan bir program yazalım. Bu programda tek bağlantı nesnesi üzerinden farklı 2 adet komutu nasıl yürüteceğimizi göreceğiz :

 

 

using System;

using System.Collections.Generic;

using System.ComponentModel;

using System.Data;

using System.Data.SqlClient;

using System.Drawing;

using System.Text;

using System.Windows.Forms;

 

namespace MARSOrnegi

{

    public partial class Form1 : Form

    {

        public Form1()

        {

            InitializeComponent();

        }

 

        private void btnSorgula_Click(object sender, EventArgs e)

        {

            try

            {

                SqlConnection con = new SqlConnection("data source=.;initial catalog=Calisma;uid=****;password=********;MultipleActiveResultSets=true");

 

                SqlCommand cmd1 = new SqlCommand("Select * From Musteriler");

                SqlCommand cmd2 = new SqlCommand("Select * From Urunler");

 

                cmd1.Connection = con;

                cmd2.Connection = con;

 

                SqlDataReader dr1;

                SqlDataReader dr2;

 

                con.Open();

 

                dr1 = cmd1.ExecuteReader();

                dr2 = cmd2.ExecuteReader();

 

                lstMusteriler.Items.Clear();

                while (dr1.Read())

                {

                    lstMusteriler.Items.Add(dr1["Ad"].ToString()+" "+dr1["Soyad"].ToString());

                }

               

                lstUrunler.Items.Clear();

                while (dr2.Read())

                {

                    lstUrunler.Items.Add(dr2["UrunID"].ToString()+" "+dr2["UrunAdi"].ToString());

                }

 

                con.Close();

            }

            catch (SqlException ex)

            {

                MessageBox.Show(ex.Message);

            }

        }

    }

}

 

Yukarıda görmüş olduğunuz kod MARS yapısını kullanarak aynı database içerisindeki iki ayrı tabloyu sorgulayıp kullanıcının karşısına getirir. Bunu yaparken sql komutları birbirinin bitmesini beklemez ve ikiside aynı bağlantı üzerinde koşar. Böylece hem sistem kaynaklarında gereksiz bir tüketimi engellemiş oluruz hemde kullanıcıya istediği bilgiyi daha çabuk döndürmüş ve son olarak da bazen müşterilerimizden çıkan ?Bu program çok yavaş çalışıyor? şikayetinden bir ölçüde kurtulmuş oluruz.

 

      Şimdi gelelim MARS?ın uygulanabilme şartlarına. MARS?ı kullanabilmek için sadece MARS yapısını destekleyen bir veritabanı sistemi ile çalışıyor olmak yeterli. Tabiki ADO.NET 2.0 ?ı unutmamak lazım Visual Studio 2005 bu aşamada sorununuzu çözecektir.Bunlar dışında MARS? tan faydalanabilmek için connectionstring property mize  ?MultipleActiveResultSets=true? ifadesini eklemeyi unutmuyoruz. Bu ifade eklendiği takdirde veritabanı sistemimiz bizim MARS yapısına dayanan bir uygulama geliştirdiğimizi anlıyor ve komutlarımızı buna göre yorumlamaya başlıyor.

 

      Makalemizin en başından beri birçok yerde eş zamanlı çalışmak şeklinde bir ifade geçti. Bunun ne anlama geldiğine bir sonraki makalemizde değiniyor olacağız. Şimdilik herkese iyi günler diliyorum, bir sonraki makalede görüşmek dileğiyle.

 

 

Not: Yukon içerisindeki Calisma isimli databasedeki tablolar

 

Musteriler :

 

[Ad] [varchar](50) COLLATE Turkish_CI_AS NULL

[Soyad] [varchar](50) COLLATE Turkish_CI_AS NULL

 

 

Urunler :

 

[UrunID] [int] IDENTITY(1,1) NOT NULL

[UrunAdi] [varchar](50) COLLATE Turkish_CI_AS NULL

 

 

Bora BURGUCUGİL

E-mail : bora.burgucugil@bilgeadam.com

 

BilgeAdam BTA

Bireysel Yazılım Geliştirme Eğitmeni

Beşiktaş


Collection Base

COLLECTION BASE SINIFI ILE KENDI KOLEKSIYONLARIMIZI YAZMAK

               

                Bu makalemizde CollectionBase sınıfından yararlanarak kendi koleksiyonumuzu yazıyor olacağız. Öncelikle koleksiyonların ne olduğunu hatırlayalım. Koleksiyonları ilk etapta bir dizi gibi düşünebiliriz.  Diziler aynı tipten veya farklı tiplerden birçok değeri taşımak için kullandığımız referans tipli yapılardır.Örnek olarak 5 gözlü bir integer dizisi için tanımlama aşağıdaki gibi oluyordu :

int[] sayilar = new int[5];

Bu şekilde tanımladığınız bir dizi ile 5 adet integer bilgiyi taşıyabiliriz. Böyle bir yapıda canımızı sıkan iki nokta var :

  1. Tüm değerlerin integer olması gerektiği, başka bir bilgi taşıyamıyor olmamız
  2. 5 sayıdan fazla taşımak istersek Array.Resize metotunu kullanmak zorunda kalmamız (ki kendisi C# a 2.0 ile birlikte eklenmiştir J)

Bu iki problemin birincisinden object dizisi kullanarak kolayca kurtulabiliyoruz. Fakat bununda yanında getirdiği bazı problemler var. Bu problemler den biri bu koleksiyonun içerisine object olduğu için herşeyi ekleyebiliyor olmamız.

İkinci problemden ise ArrayList veya benzeri bir koleksiyon kullanarak kurtulabiliyoruz.

ArrayList koleksiyonunda da biraz önce bahsettiğimiz problem yine geçerli. Koleksiyonları hem resize işlemlerinden kurtulmak için hemde object türünden değerler taşıdıklarından istediğimiz tiple çalışmak için tercih ederiz.Fakat  bir yazılım geliştirme ekibi içerisinde çalıştığınızı düşünürseniz ve siz sadece dll hazırlamak ile uğraşıyorsanız, tip güvenliğine önem vermeniz gerekecektir. Örneğin bir Ogrenci Takip programı yazarken öğrencilerin listesinin tutulduğu koleksiyonda bir DateTime değerin durması pek hoş olmayacaktır. Sebebi ise o koleksiyonu bir gridde veya dropdownlist içerisinde DataSource olarak kullanamayacak olmanız. Bu örnekler daha da çoğaltılabilir.

Framework 2.0 ile birlikte Generic tipler sayesinde çözülen bu problem 1.1 versiyonunda çalışırken CollectionBase vb sınıflar ile çözülüyordu. Bu makalemizde ki konumuz ise CollectionBase sınıfı ile bu işlemi nasıl çözüyor  olduğumuz.

CollectionBase sınıfı bir taban sınıf olduğundan dolayı kendisini instance çıkartarak kullanamıyorsunuz.  Aşağıda CollectionBase sınıfı ile ilgili bir metadata bilgisi yer almaktadır.

namespace System.Collections

{

    [Serializable]

    [ComVisible(true)]

    public abstract class CollectionBase : IList, ICollection, IEnumerable

    {

        protected CollectionBase();

        protected CollectionBase(int capacity);

        [ComVisible(false)]

        public int Capacity { get; set; }

        public int Count { get; }

        protected ArrayList InnerList { get; }

        protected IList List { get; }

 

        public void Clear();

        public IEnumerator GetEnumerator();

        protected virtual void OnClear();

        protected virtual void OnClearComplete();

        protected virtual void OnInsert(int index, object value);

        protected virtual void OnInsertComplete(int index, object value);

        protected virtual void OnRemove(int index, object value);

        protected virtual void OnRemoveComplete(int index, object value);

        protected virtual void OnSet(int index, object oldValue, object newValue);

        protected virtual void OnSetComplete(int index, object oldValue, object newValue);

        protected virtual void OnValidate(object value);

        public void RemoveAt(int index);

    }

}

      Metadata gibi bilgilerle cok fazla mesgul olmadan asıl kodlarımıza geçiyoruz. Öncelikle Ogrenci sınıfımızı hazırlayalım.

public class Ogrenci

    {

        static int sayac = 0;

        public Ogrenci()

        {

            this._siraNo = ++sayac;

        }

        int _siraNo;

        public int SiraNo

        {

            get { return _siraNo; }

        }

        string _isim;

        public string Isim

        {

            get { return _isim; }

            set { _isim = value; }

        }

        string soyIsim;

        public string SoyIsim

        {

            get { return soyIsim; }

            set { soyIsim = value; }

        }

        public override string ToString()

        {

            return "Adı - Soyadı : " + this._isim + " " + this.soyIsim;

        }

    }

      Class hakkında ufak bir açıklama yapmak gerekirse, öğrenci ile ilgili isim soyisim ve sira numarası gibi bilgilerimizi taşıyoruz. Fakat SıraNo değeri kullanıcı tarafından değil sistem tarafından veriliyor. Her instance oluşturulduğunda sınıftaki constructor sayesinde static ve private olan bir değişken bir arttırılıyor böylece sıra numarası sırayla birer birer arttırılıyor.    

      Şimdi gelelim koleksiyonumuzu oluşturmaya :

 

public class Sinif:CollectionBase

    {

        public void Ekle(Ogrenci ogr)

        {

            this.List.Add(ogr);

        }

 

        public void Ekle(Ogrenci ogr, int index)

        {

            this.List.Insert(index, ogr);

        }

 

        public void Sil(Ogrenci ogr)

        {

            if (this.List.Contains(ogr))

                this.List.Remove(ogr);

        }

        public void Sil(int index)

        {

            if (this.List.Count > index)

                this.List.RemoveAt(index);

        }

 

        public Ogrenci this[int index]

        {

            get { return (Ogrenci)this.List[index]; }

            set { this.List[index] = value; }

        }

    }

 

CollectionBase sınıfından türeme işlemi yaptığınız zaman sınıfınıza miras yoluyla List adında bir koleksiyon gelmektedir.IList türünden olan bu koleksiyon object türünden değer taşır ve önemli olan bu üye sınıfınıza protected olarak geçmektedir. Yani List ismindeki üyemizden kimsenin haberi yok J

Koleksiyon sınıfımıza iki adet ekle metotu iki adet sil metotu ve bir adet indexer dediğimiz tüm koleksiyonlardan alışık olduğunuz :

ArrayList liste = new ArrayList();

liste.Add(?123?);

liste[0]=?Abc?;

şeklinde kullandığımız indeksleyici bulunmakta. Bunları hazırladıktan sonra artık bu uygulamamızı kullanacak olan bir windows application hazırlamaya başlayalım. Aşağıdaki gibi bir form tasarımı hazırladım :

 

En üstten en alta doğru sırasıyla TextBox isimlerimiz :

·         txtAdi

·         txtSoyadi

·         txtSiraNo

·         txtAramaAdi

·         txtAramaSoyadi

Aşağıda ise Form1 içerisinde koleksiyonun kullanımının kodları bulunmakta, önce kodları inceleyelim sonra da kodlar üzerine konuşalım :

 

using System;

using System.Collections.Generic;

using System.ComponentModel;

using System.Data;

using System.Drawing;

using System.Text;

using System.Windows.Forms;

 

namespace CollectionBaseMakale

{

    public partial class Form1 : Form

    {

        public Form1()

        {

            InitializeComponent();

        }

 

        void Doldur()

        {

            listBox1.Items.Clear();

            foreach (Ogrenci ogr in liste)

            {

                listBox1.Items.Add(ogr);

            }

        }

 

        Sinif liste = new Sinif();

        private void btnEkle_Click(object sender, EventArgs e)

        {

            Ogrenci ogr = new Ogrenci();

            ogr.Isim = txtAdi.Text;

            ogr.SoyIsim = txtSoyadi.Text;

            liste.Ekle(ogr);

            this.Doldur();

        }

 

        private void btnBul_Click(object sender, EventArgs e)

        {

            if (!string.IsNullOrEmpty(txtSirano.Text))

            {

                int aranan = Convert.ToInt32(txtSirano.Text);

                foreach (Ogrenci ogr in liste)

                {

                    if (ogr.SiraNo == aranan)

                    {

                        txtAramaAdi.Text = ogr.Isim;

                        txtAramaSoyadi.Text = ogr.SoyIsim;

                        break;

                    }

                }

            }

            else

                MessageBox.Show("Arama işlemi için sıra numarası girmelisiniz!");

 

            this.Doldur();

        }

 

        private void btnDegistir_Click(object sender, EventArgs e)

        {

            if (!string.IsNullOrEmpty(txtSirano.Text))

            {

                int aranan = Convert.ToInt32(txtSirano.Text);

                foreach (Ogrenci ogr in liste)

                {

                    if (ogr.SiraNo == aranan)

                    {

                        ogr.Isim = txtAramaAdi.Text;

                        ogr.SoyIsim = txtAramaSoyadi.Text;

                        break;

                    }

                }

            }

            else

                MessageBox.Show("Arama işlemi için sıra numarası girmelisiniz!");

            this.Doldur();

        }

 

        private void btnSil_Click(object sender, EventArgs e)

        {

            if (!string.IsNullOrEmpty(txtSirano.Text))

            {

                int aranan = Convert.ToInt32(txtSirano.Text);

                foreach (Ogrenci ogr in liste)

                {

                    if (ogr.SiraNo == aranan)

                    {

                        liste.Sil(ogr);

                        MessageBox.Show("Silme işlemi tamamlandı!");

                        break;

                    }

                }

            }

            this.Doldur();

        }

    }

}

 

Yukarıdaki kodlarımızı açıklamaya başlayalım. Öncelikle Doldur ismindeki metot en alttaki listbox kontrolünü her işlemden sonra doldurmakla görevli. Onun haricinde görüldüğü üzere Global olarak bir Sinif nesnesi tanımlanmış. Daha sonra ekle düğmesine basıldığı zaman bu koleksiyona yeni bir öğrenci nesnesi ekleniyor. Tabiki otomatik olarak bir sıra numarası alıyor. Bul diyince sıra numarasına göre arama yapılıp aranan öğrenci bulunuyor. Değiştirme ve silme işlemide aynı bu yöntemle çalışıyor.

Bizim için asıl önemli olan konu koleksiyonumuzun özel bir tiple çalışıyor olması. Hazırladığımız koleksiyon object tipinden veriler kabul ederek değil de Ogrenci sınıfı ile çalışıyor böylece hazırladığınız koleksiyonda başka bir tip kullanma şansınız kalmıyor.

 

Bu makalede CollectionBase isimli sınıfa değinmiş olduk. Bir başka makalede görüşmek üzere hepinize iyi çalışmalar.

 

 

Sorularınız için

bora.burgucugil@bilgeadam.com

adresine mail atabilirsiniz.

 


Method Overloading in XML Web Services

Method overloading XML Web Servislerinde default olarak desteklenmemektedir. Fakat bu işlemi uygulayabilmemiz için özel bir attribute bildirimi yapılabilmektedir. MessageName isimli attribute ile web servislerinde method overloading uygulayabiliyorsunuz. Bu noktada karşınıza eğer 2.0 veya üstü bir Framework versiyonu ile çalışıyorsanız,

[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]

satırından kaynaklanan bir hata alırsınız. Hata web servis içeriğinin BasicProfile1_1 kurallarına uymadığı ile ilgilidir. Bu satırın anlamı :

Yazmış olduğunuz web servisin Web Services Interopability Organization's (WS-I) Baisc Profile 1.1 standartlarına uyması gerekliliğidir. Bu standartlardan bir tanesi ise web servislerin metot overloading e uymaması daha açık bir ifade ile, metot isimlerinde unique kuralının arandığıdır. Bu hatayı düzeltmenin yolu ya o satırı silmek ki pek fazla tercih etmediğimiz bir yoldur :)  Bir diğer yol ise attribute bilgisini aşağıdaki gibi değiştirmektir.

[WebServiceBinding(ConformsTo = WsiProfiles.None)]

İyi çalışmalar


Imagine Cup 08

Imagine Cup 2008 bu senede yazılım sektöründe çok önemli yer tutacak. Bu sene içerik "sürdürülebilir çevre için, teknolojinin kullanıldığı bir dünya düşleyin" olarak belirlendi. Her sene olduğu gibi bu sene de yakından takip etmenizi öneriyorum :) Detaylı bilgiye buradan erişebilirsiniz