Makale Özeti

Bu makalemde sizlerle DataTable özelliklerini taşıyan bir CollectionBase class’ının nasıl yazılabileceğini ve hangi özellikleri ne şekilde uyarlayacağımızı çeşitli performans testleri eşiliğinde inceleyip çoğumuzun karşılaştığı bir soru olan çoklu veri taşımada DataTable mı kullansam yoksa Collection mu kullansam sorusuna cevap arayacağız. VeCollectionBase’imizi Generic kullanarak kodlarsak her entitymiz için kullanmamız kolay olacaktır. Bunun yanı sıra DataTable'ı DataAdapter ın Fill Metodunu kullanarak doldurduğumuz kolaylıkta Collectionumuzu doldurabiliyor olacağız.

Makale

            Merhabalar,

            Bu makalemde sizlerle
 DataTable özelliklerini taşıyan bir CollectionBase class’ının nasıl yazılabileceğini ve hangi özellikleri ne şekilde uyarlayacağımızı çeşitli performans testleri eşiliğinde inceleyip çoğumuzun karşılaştığı bir soru olan çoklu veri taşımada DataTable mı kullansam yoksa Collection mu kullansam sorusuna cevap arayacağız.

            Öncelikle CollectionBase’imizi Generic kullanarak kodlarsak her entitymiz için kullanmamız kolay olacaktır. Kodlama yaparken bunu göz önünde bulundurmalıyız. Ancak DataTable i DataAdapter ın Fill Metodunu kullanarak doldurduğumuz kolaylıkta Collectiona veri doldurmak için ciddi bir performans problemi olarak gözönüne alınması gereken Reflection kullanacağız. Buna rağmen ileriki testlerimizde Reflectionun yazdığımız koda olan olumsuz performans etkisinin sanıldığı kadar olmadığını göreceğiz.

            Artık CollectionBase classımızı yazmaya başlayabiliriz. Ismini MyCollection verdiğimiz classımızı CollectionBase classından türeteceğiz ve IList interface’inin Generic tipini inherit ederek kullanacağız.

            public class MyCollection<T> : CollectionBase, IList<T>
            {


            Şimdi ise en önemli kısıma gelelim; verileri Collectionumuza doldurmak için her sefer Data Katmanına veya kod kısmımıza uzun uzun kodlar yazmak istemiyoruz. Bunun için classımıza public bir metod yazarak tüm işlemi burada gerçekleştirebiliriz. Bu metodumuz dışarıdan DataReader alacak ve kendi içerisinde DataReader’dan gelen verilere göre generic tipinin instance' ini alacak propertylerine değerleri atayıp Collectiona ekleyecektir.

                        public void SetDataFromReader(DbDataReader dr)
                        {
                                    Type assemblyType = typeof(T).Assembly.GetType(typeof(T).FullName);
                                    while (dr.Read())
                                    {
                                                T a = (T)Activator.CreateInstance(assemblyType);
                                                foreach (PropertyInfo pi in assemblyType.GetProperties())
                                                {
                                                            if (dr[pi.Name] != null)
                                                            {
                                                                        pi.SetValue(a, dr[pi.Name], null);
                                                            }
                                                }
                                                InnerList.Add(a);
                                    }
                        }
            }

            Evet şimdi yazdığımız bu metodu inceleyelim. Bu metodda ilk önce collectionumuzu yaratırken belirlediğimiz T geenric tipimize ait classımızın tipini alıyoruz. Daha sonrasında ise DataReaderda gelen her kayıt için Classımızın bir instance’ini alıyor ve bunu referans tipi T  olarak belirlenmiş a adındaki değişkenimize atıyoruz. Daha sonra generic tipimizin(Entity Class) içinde bulunan propertyleri reflection ile okuyor herbiri için Gelen DataReaderda karşılık gelen kayıt olup olmadığına bakıyoruz. Eğer karşılık varsa PropertyInfo Classının SetValue metodunu kullanarak bu propertylere değerlerini atıyoruz. Şimdi DataReader'ın bir sonraki kayıdına geçebiliriz. Ancak öncelikle burada oluşturduğumuz ve propertylerine değer atadığımız nesnemizi Collectiona InnerList.Add metodunu kullanarak ekliyoruz.
   
            Şimdi ise bu işlemin gerçekleştirildiği örnek koları inceleyelim.
            Öncelikle veritabanından gelen verileri taşıyacak yapımız olan entity mizi oluşturalım.

            public class SampleEntity
            {
                        private int mSampleId;
                        public int SampleId
                        {
                                    get { return mSampleId;}
                                    set{mSampleId = value;}
                        }
                        private string mSampleText;
                        public string SampleText
                        {
                                    get{return mSampleText;}
                                    set{mSampleText = value;}
                        }
                        private DateTime mSampleDate;
                        public DateTime SampleDate
                        {
                                    get{return mSampleDate;}
                                    set{mSampleDate = value;}
                        }
                        private Guid mSampleGuid;
                        public Guid SampleGuid
                        {
                                    get{return mSampleGuid;}
                                    set{mSampleGuid = value;}
                        }
            }


            Şimdi ise bu entitylerimizi taşıyacak Collection Classımızı oluşturalım.Biraz önce yazmış olduğumuz MyCollection classını temel alarak ne kadar oluşturacağımızı görelim.

            public class SampleCollection : MyCollection<SampleEntity>
            {
            }


            Sanırım sizde bu kadar kısa bir kod olmasını beklemiyordunuz. Simdi ise bu collectionu database den nasıl dolduracağımızı inceleyelim.

            private void Form1_Load(object sender, EventArgs e)
            {
                        SampleCollection s = new SampleCollection();
                        DbProviderFactory ProviderFactory = DbProviderFactories.GetFactory("System.Data.SqlClient");
                        DbConnection Connection = ProviderFactory.CreateConnection();
                        Connection.ConnectionString = "data source=.;initial catalog=MyCollectionTest;integrated security=SSPI";
                        DbCommand cmd = ProviderFactory.CreateCommand();
                        cmd.CommandText = "Select * FROM Sample";
                        cmd.Connection = Connection;
                        DbDataReader dr;
                        Connection.Open();
                        dr = cmd.ExecuteReader();
                        s.SetDataFromReader(dr);
                        Connection.Close();
                        dataGridView1.DataSource = s;
            }

           

            Burada yazılı olan temel ADO.Net kodlarını açıklamıyorum. Ancak BaseCollectionumuz olan MyCollection’un DataReader’ı parametre olarak alan ve Collectionu dolduran metodun nasıl kullanıldığını göstermek istedim.

            Şimdi ise performans testlerimizi inceleyelim. Testler SQL Server 2005’den çekilen 100.000 veri için DataTable veya biraz once yazdığımız MyCollection classından türemiş bir Collectionun doldurulması ve DataGridde Gösterilmesi temel alınarak 100 deney üzerinden yapılmıştır.



Datanin sql den cekilmesinden DataTable a veya MyCollection a doldurulmasına kadar geçen surenin grafiği. Bu grafikte reflection kodu barındırmadığı için DataTable zaman zaman daha hızlı çalışıyor.


Bu veriler ise Datanın SQL Serverden çekilmesi DataTable veya Collectiona doldurulması ve DataGridde gösterilmesi adımlarını kapsamaktadır. Toplamda ise Collection daha kısa sürede işlem yapmaktadır.

Tabiiki SetDataFromReader metodunu her collectionumuzda override edip Entitymizin kolonlarına yani propertylerine göre entitymizi kodla her collection için tek tek oluşturma kodlama maliyetini göze alırsak reflectionun olumsuz etkilerinden kurtulmuş olacağız ve kodumuz daha hızlı çalışacaktır.

Makalenin ikici kısmında ise Collectionumuzda Gui Tarafında Değişiklik yapıldığında entitylerimizin Statelerini DataRow benzeri nasıl tutabileceğimizi Collectionumuza DataTable da bulunan AcceptChanges,RegectChanges,GetChanges gibi metodları nasıl implement edebileceğimizi inceleyeceğiz.

Tamer ÖZ

oztamer@hotmail.com
tamer.oz@yazgelistir.com
oztamer@hotmail.com
Ozel Bir Collection II - Verinin State'ini Tutmak

Ozel Bir Collection III - Verinin State'ini Tutmak