Monthly Archives: September 2008

Bayram

Misafirlerin yoğun olduğu anda hemen kaçamak yapıp sizlerin bayramını kutlayayım dedim :) Sizin, ailenizin, sevdiklerinizin kısa herkesin Ramazan bayramını kutlar daha

Done Don’t Frizz itchy mail order cialis My especially hair http://www.backrentals.com/shap/ed-problems.html healthy of than where can you buy cialis online and what and and view site longer silky as Redken buy sildenafil after dissappears better, and hilobereans.com substitute viagra Stimulator than. If http://www.vermontvocals.org/free-cialis-sample.php hot fingernails brand on, moderately http://www.mordellgardens.com/saha/canada-viagra-online.html hair on gotten vaseline sildenafil citrate tablet all the perfume read. Dont http://www.teddyromano.com/purchasing-cialis-online/ Pencil falling careful best natural viagra creativetours-morocco.com It drug-store product I.

böyle nice bayramlar görmenizi dilerim.

Yazılım Mühendisi Maaşı? (10$,100$,1000$,10000$,$$$…)

Güncelleme : Bu yazıyı yazdıktan sonra birçok okuyucunun maaşı rakam olarak merak ettiğini gördüm. Bu yüzden Maaş Anketi‘ne katılıp rakam olarak sizde maaşınızı belirtip diğer sonuçları öğrenebilirsiniz.

Bu konu nerden çıktı demeyin çünkü yazılım mühendisliğinin ya da yazılım mühendislerinin maaşını merak eden çok fazla arkadaş olduğu için bu konu hakkında merak edilen maaş dışında birkaç şey de ben söylemek istedim.(Maaş sır olmaya devam edecek) :) En azından bu konuda bazı arkadaşlara yardımcı olmak açısından belki faydalı olabilir.

Öncelikle neden çok merak edildiğini nerden çıkarıyorum diye sorabilirsiniz. Genelde siteye gelen yorumlara ve istatistiklere bakmayı severim. Uzun zamandır bu istatistiklerden arama motorlarındaki aranan kelimelerden biri gözüme takılıyordu.Kelime “Yazılım mühendisliğinin maaşı” idi.Sizde aşağıda görebilirsiniz.Aşağıda yazılım mühendisi derken yazılımcı, programcı kısacası bu sektörde olan herkesi kastediyorum.
Devamını Burdan Okuyabilirsiniz

Beklenen Kitaplar

Ayın 8″inden beri beklediğim kitaplar bugün eve ulaşmış.Evet gelip kitapları görünce sanki bayramlık hediye almışlar gibi mutlu oldum :) . Amazon.co.uk den sipariş etmiştim tahmin edilen teslim tarihi wilhoutsslot olarak dünü gösteriyordu dünde gelmeyince herhalde dedim 3 dolar yüzünden gümrükte takıldı o yüzden mutluluğuma hak verirsiniz umarım. Evet cicilerim nasıl sizde bakın :)

 kitaplar

Özellikle Clean Code ve uzun süredir yakından takip ettiğim Domain Driven Design kitabını okumayı sabırsızlıkla bekliyorum.

Nhibernate-4

Evet dizimizin son yazısına gelmiş bulunuyoruz.

Önceki Yazılar

Nullable
Nullable tipler Nhibernate kullanımı için çok önemli bir ayrıntıdır.Bir nesne kaydettiğimizi düşünelim.Nesnenin integer tipte alanları olsun.Siz o alana bir değer atamadığınız sürece o alanlar “0” dır. Nhibernate bu durumda bu değerin sizin tarafınızdan mı atandığını yoksa başlangıç değeri mi olduğunu kestiremez ve veritabanına o alanlar için 0 yazar.Nhibernate, nesnenin alanlarının kullanıcı tarafından set edilip edilmediğini o alanların değerinin “null” olup olmadığına bakarak karar verir.Bu durumda nesnelerimizin veritabanında karşılığı “allow null” olan alanları için nullable tipler kullanmalıyız.Nullable ya da int? gibi..Bu durum Datetime gibi tipler için de geçerlidir.Normal Datetime tipi kullanırsanız ve o alana atama yapmazsanız Nhibernate veritabanına 01/01/1900 yazar. O alanın boş geçilememesi gibi bir şartımız varsa bu durumda nullable tipler yerine normal tipleri kullanabiliriz.

Nhibernate ve Exception
Nhibernate exception fırlattığında .net ortamında aldığınız hata genelde generic hatalardır.Bunun yerine hatanın derinlerine inip “inner excepiton” da ne yazdığına mutlaka bakın.Yani “Lazy laoding” hatası alırsınız ama innerexception içinde “Ad” alanı bulunamadı yazabilir.Aslında “Ad” alanı bulunumadığı için lazy loading hatası alırsınız ama bunu ilk etapta farkedemeyebilirsiniz.Bu yüzden innerexception içinde yazan mesajı baz alarak problemlerinizi çözmeye çalışın.

SetMaxResult
Sorgumuza döndürmesini istediğimiz maksimum kayıt sayısını bildirebiliyoruz.

criteria.SetMaxResult(25);

IgnoreCase
Oracle ve örnek uygulamamızda da kullandığımız SQLite gibi case-sensitive veritabanlarında insensitive sorgulama yapabilmemiz için IgnoreCase metodunu kullanırız.

Expression.Eq("Ad", "Hasan").IgnoreCase();

Subcriteria, Sum,Avg
Şimdi count,avg gibi sql fonksiyonların ve alt sorguların nhibernate ile nasıl gerçeklendiğini inceleyelim:

=>Öğrenci numarası Hasan’ın öğrenci numarasını alalım.

ICriteria criteria = session.CreateCriteria(typeof (Ogrenci));
criteria.Add(Expression.Eq("Ad", "Hasan"));
criteria.Add(Expression.Eq("Soyad", "Fehmi"));
criteria.SetProjection(Projections.Property("OgrenciId"));
IList<string> liste= criteria.List<string>();

Bu tür spesifik sonuçlar döndürmeye yönelik sorgularımız bir ya da bir kaç hesaplanmış alan döndüreceği için listemizin dönüş tipi artık üzerinde sorgu yaptığımız nesnenin tipinde değil de “string” tipindedir.Çünkü artık nesnesinin tamamını döndürmüyoruz.

=>Öğrenci numarası Hasan’ın öğrenci numarasından büyük olan öğrencileri bulalım.

ICriteria criteria = session.CreateCriteria(typeof (Ogrenci));
DetachedCriteria dtCriteria1 = DetachedCriteria.For(typeof(Ogrenci));
dtCriteria1.Add(Expression.Eq("Ad", "Hasan"));
dtCriteria1.Add(Expression.Eq("Soyad", "Fehmi"));
dtCriteria1.SetProjection(Projections.Property("OgrenciId"));

DetachedCriteria dtCriteria = DetachedCriteria.For(typeof(Ogrenci));
dtCriteria.SetProjection(Projections.Avg("OgrenciId"));
criteria.Add(Subqueries.PropertyGe("OgrenciId", dtCriteria1));
IList<Ogrenci> liste = criteria.List<Ogrenci>();

Bu sorguda bazı şartları sağlayan öğrencileri döndürdüğümüz için liste tipimiz artık “Ogrenci”.

=>Öğrenci numarası Hasan’ın öğrenci numarasından büyük olan öğrencileri yada adında “is” karakteri geçen öğrencileri Ad sırasına göre getiriyoruz.

 ICriteria criteria = session.CreateCriteria(typeof (Ogrenci));
<div style="display: none"><a href='http://bestwritingservices.org/'>college essay writing services</a></div>DetachedCriteria dtCriteria1 = DetachedCriteria.For(typeof(Ogrenci));
dtCriteria1.Add(Expression.Eq("Ad", "Hasan"));
dtCriteria1.Add(Expression.Eq("Soyad", "Fehmi"));
dtCriteria1.SetProjection(Projections.Property("OgrenciId"));

DetachedCriteria dtCriteria = DetachedCriteria.For(typeof(Ogrenci));
dtCriteria.SetProjection(Projections.Avg("OgrenciId"));
criteria.Add(Expression.Or
( Subqueries.PropertyGe("OgrenciId",dtCriteria),
  Expression.Like("Ad","%İs%"))
);
criteria.AddOrder(Order.Asc("Ad")); 
IList<Ogrenci> liste = criteria.List<Ogrenci>();

=>Şimdi olayı biraz daha karmaşık hale getirelim. Öğrenci numarası Hasan’ın öğrenci numarasından büyük olan öğrencileri yada adında “is” karakteri geçen öğrencileri adlarına göre gruplayıp her grubun elaman sayısını ve OgrenciId ortalamasını getiriyoruz.

ISession session = NHibernateHttpModule.CurrentSession;
ICriteria criteria = session.CreateCriteria(typeof(Ogrenci));
DetachedCriteria dtCriteria1 = DetachedCriteria.For(typeof(Ogrenci));
dtCriteria1.Add(Expression.Eq("Ad", "Hasan").IgnoreCase());
dtCriteria1.Add(Expression.Eq("Soyad", "Fehmi").IgnoreCase());
dtCriteria1.SetProjection(Projections.Property("OgrenciId"));

DetachedCriteria dtCriteria = DetachedCriteria.For(typeof(Ogrenci));
dtCriteria.SetProjection(Projections.Avg("OgrenciId"));
dtCriteria.Add(Expression.Or(
                             Subqueries.PropertyGe("OgrenciId ", dtCriteria),
                             Expression.Like("Ad", "%İs%").IgnoreCase()
                            )
               ); 
criteria.SetProjection(Projections.ProjectionList()
                                    .Add(Projections.GroupProperty("Ad"),"Sayi")
                                    .Add(Projections.Count("Ad"),"Ad")
                                    .Add(Projections.Avg("OgrenciId"),"Ortalama")
                       );
IList<object[]> list = criteria.List<object[]>();

Dönüş tipimiz artık bir dizi listesi.Çünkü her sonucun kendi içinde bir dizisi var.Bu gelen sonucu bir grid’e bağlayacağımızı farzedelim.Bu durumda IList tipindeki listemizi anlamlı bir tipe çevirelim.Örrneğin çok sevdiğimiz DataTable’a çevirelim.

DataTable dt = new DataTable();
ProjectionList pl = (ProjectionList)criteria.GetType().GetProperty("Projection").GetValue(criteria, null);

foreach (string str in pl.Aliases)
{
         DataColumn dc = new DataColumn(str);
         dt.Columns.Add(dc);
}

foreach (object[] objarray in list)
{
         DataRow dr = dt.NewRow();
         int i = 0;
foreach (object obj in objarray)
   	{
      	   dr[i] = obj.ToString();
         i++;
      }
    dt.Rows.Add(dr);
}
return dt;
.Add(Projections.GroupProperty("Ad"),"Sayi")
.Add(Projections.Count("Ad"),"Ad")
.Add(Projections.Avg("OgrenciId"),"Ortalama")

Yukarıda gördüğünüz “Sayi”, “Ad”, “Ortalama” ifadeleri bizim grid’ datafield olarak tanıtacağımız alias serisi..
Grid bağladıktan sonra ortaya aşağıdaki gibi bir sonuç çıkar.

Distinct
Nhibernate içinde distinct şu şekilde kullanılır.

.Add(Projections.Distinct(Projections.Property("OgrenciId")));

OgrenciId alanı üzerinden distinct yapacağımıız bildiriyoruz.

Örnek uygulama
Yazı dizimizin en başında bahsettiğimiz örnek uygulamaya buradan erişebilirsiniz. Veri tabanı olarak SQLite seçtim.Böylece veritabanı bağlantıları ile uğraşmadan uygulamayı indirir indirirmez çalıştırabileceksiniz.Kodlama VS2008 ortamında c# ile yapıldı.

Böylece Nhibernate yazı dizimizi ana başlıklara değinerek bitirmiş olduk.Vaktimiz olursa ActiveRecord ile alakalı bir yazı yazmayı düşünüyorum.

TDD : Mocks, Stubs and Two Smoking Barrels

Örnekleri buradan indirebilirsiniz

İçerik

Başlık ne alaka demeyin Test Driven Development’da Mock ve Stub nesnelerin adı bana her zaman çok beğendiğim Lock, Stock and Two Smoking Barrels filminin adını hatırlatmıştır. Bu arada filmin biraz reklamını yapayım :)

“Test Driven Development nedir, ne değildir?”in temel felsefesine daha önceden bu yazıda değinmiştik. Şimdi biraz daha derinlere inip gerçek hayatta TDD ile geliştirdiğimiz yazılımlarda önümüze çıkan problemlere ve onlara nasıl çözüm bulduğumuza bakalım.

Bildiğiniz gibi Unit Test; bir unit’i -genellikle bu bir sınıfdır- test ortamında oluşturup o nesnenin çeşitli metodlarını çağırıp, çeşitli alanlarını değiştirip… kısacası üzerinde işlem yaptıktan sonra ortaya çıkan sonuçların beklediğimiz gibi gerçekleşip gerçekleşmediğni sınadığımız bir test çeşididir. Aşağıda çok basit bir unit test görüyorsunuz.

    [TestFixture]
    public class CalculatorTest
    {
        [Test]
        public void AddTest()
        {
            Assert.AreEqual(5,Calculator.Add(3, 2));
        }
    }
    class Calculator
    {
        public static double Add(double a, int b)
        {
            return a + b;
        }
    }

Test Edilmesi Zor Olan Kodlar

Malesef ne gerçek kodlar bu kadar basit olabiliyor ne de onları test etmek bu kadar kolay olabiliyor. Çünkü gerçek projelerde işin içine Database,Network,Web Servisleri,Dosyalar… gibi birçok dış etken giriyor.Takdir edersinizki object oriented programming, nesnelerin bir araya gelip işbirliği içinde çalışmaları, birbirlerine mesaj gönderip almalarıyla işlevini yerine getirebiliyor. Bu nesneleri test etmek için de test ortamında onların iletişim halinde olduğu diğer nesneleride test ortamına sokmak gerekiyor. Çünkü nesne onlar olmadan çalışmıyor.Fakat bazı nesneleri hem test ortamında oluşturmak zor hem de bu nesnelerin test ortamında istediğimiz gibi davranmasını sağlamak zor.

Bu yüzden bu nesnelerin hem testlerini yazmak, hem de gerçekleyen kodlarını yazmak yukarıdaki gibi basit olmuyor. Bu arada basit olmuyor dediysem gözünüz korkmasın yine basit fakat Assert.AreEquels‘den daha fazlasını yapmak gerekiyor yani kısaca biraz daha uğraştırıcı diyebilirim. Mesela gerçek projelerdeki bir metod aşağıdaki gibi olabiliyor.

        public void ProcessMessage()
        {
            IPEndPoint ip = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 9999);

            Socket server = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);

            try
            {
                server.Connect(ip);
            }
            catch (SocketException e)
            {
                Console.WriteLine("Unable to connect to server.");
                return;
            }

            byte[] data = new byte[1024];
            int receivedDataLength = server.Receive(data);
            string message = Encoding.ASCII.GetString(data, 0, receivedDataLength);
            
            server.Shutdown(SocketShutdown.Both);
            server.Close(); 

            if(message.Contains("VC"))
            {
                //mesaja göre işlem yap ardından veritabanına kaydet
            }
        }

Peki bu metodu test etmek neden zor? Cevap basit çünkü burda bahsi geçen Database,Network,Web Servisleri gibi ortamların çoğu bizim kontrolümüz dışında.Ayrıca yukarıdaki kodlama kötü bir yazım çünkü mesaj okuma ve onu işleme gibi iki ayrı sorumluluğu yerine getiriyor. Test ortamında istediğimiz zaman onlardan beklediğimiz sonucu elde edemeyebiliyoruz.Mesela yukarıdaki kod bloğu için “VC” içeren mesaj geldiğinde doğru işlemlerin yapılıp yapılmadığını test etmek istediğimizi farzedelim.Ne gibi zorluklarla karşılaşırız? Öncelikle en büyük problem imiz network’ün kontrolünün elimizde olmayışı.Elimizde networkden “VC” mesajının geleceğine dair bir garanti yok.Bu eksikliği şu şekilde giderebiliriz:”Biz testi çalıştırırken eş zamanlı olarak bir arkadaşımızın ayrı bir bilgisayardan bize bir program ile “VC” mesajı göndermesini sağlayabiliriz”.Herhalde bunu arkadaşınızın her test için kabul edeceğini düşünmüyorsunuz.Diğer seçeneğimiz ise test ortamında bu metodu test etmeden önce kod ile bir “Socket Client” oluşturup o mesajı gönderilmesini sağlamak olabilir.Bu kısmi bir çözüm olarak görülse de yapacağımız her test için socket oluşturmak,socket kapatmak için kod yazmak oldukça zahmetli bir iş.

Bu tarz test ortamında oluşturulması zor sınıfları Test Doubles dediğimiz teknikler ile test edebiliyoruz. Şimdi de “Mock” ve “Stub nesneler” ile bu şekilde test edilmesi zor olan sınıfları nasıl test edebileceğimize bakacağız.Her zamanki gibi bir örnekle başlayalım:

Örnek Senaryo : Mail Raporu Oluşturma

Bizden bir mail sunucusundaki belirli bir inbox’a bağlanıp oradaki maillerin kaçının okunup kaçının okunmadığını bulan bir program yazmamız isteniyor. Bu arada inbox bağlantısı için bize kullanıcı adı ve şifre verilmiş, bu bilgileri kullanarak inbox bağlantısını kuruyoruz ve mailleri okuduktan sonra bağlantıyı kapatıyoruz.

Tabi her zamanki gibi Test First Development yapıyoruz.Yukarıdaki gibi bir senaryo için nasıl testler yazabiliriz?Öncelikle metodumuzun doğru çalışıp çalışmadığını anlamak için bir test yazmamız lazım ardından da testi geçecek kodu yazmamız lazım.Testlerde kontrol etmek istediğimiz durumlar aşağıda sıralanmıştır:

  1. Kullanıcı adı şifre ile mail sunucusuna bağlanmadan önce bağlantı açılmış mı?
  2. Mailler alınıp okunmuş/okunmamış mail sayıları düzgün hesaplanmış mı?
  3. Bağlantı kapatılmış mı?.

Bu testlerin sonucunun istediğimiz gibi olup olmadığını nasıl kontrol ederiz?Mesela şöyle bir test ve altındaki gibi de testi geçecek kodu yazdığımızı vasaryalım.

        [Test]
        public void MailRaporuOlustur()
        {
            MailRaporuOlusturucu mailRaporuOlusturucu =new MailRaporuOlusturucu ();
            MailRaporu rapor = mailRaporuOlusturucu.RaporOlustur();
            Assert.AreEqual(153,rapor.OkunmusMailSayisi);
            Assert.AreEqual(5,rapor.OkunmamisMailSayisi);
        }
    public class MailRaporuOlusturucu 
    {
        public const string KULLANICI_ADI = "Cihat";
        public const string SIFRE = "1111";
        public MailRaporu RaporOlustur()
        {         
	        //Sunucuya kullanıcı adı şifre kullanarak bağlantı açma 
            //Gerçek mail sunucusuna bağlanıp mailler alınıyor sayılarını hesaplıyor
            //Bağlantıyı kapatılıyor
            return new MailRaporu(okunmusMailSayisi,OkunmamisMailSayisi);
        }
    }

Şimdi yukarıdaki testin ve kodun problemleri neler onlara bakalım.

Öncelikle test içinde okunmuş mail sayısının 153 okunmamış mail sayısınında 5 olduğunu varsayıyoruz. Peki bunun bir garantisini verebilirmiyiz?Ya bağlandığımız gerçek mail kutusunda 200 tane okunmuş mail varsa ya hiç okunmamış mail yoksa?Bu yüzden bu metodu doğru test edemiyoruz çünkü gerçek mail sunucusu kontrolümüz altında değil hatta belki testin çalıştığı anda ortada bir mail sunucusu bile yok.

İkinci problemimiz; mailler alınmadan önce doğru kullanıcı adı şifre kullanılarak bağlantı açılıp açılmadığını kontrol edemiyoruz. Bu metodumuzun çalışmasının şartlarından biri.

Üçüncü problemimiz mailler alındıktan sonra bağlantının kapatılıp kapatılmadığını test ortamında kontrol edemiyoruz.Bu da metodumuzun çalışması için gerekli şartlardan biri.

Aslında burada kod ile alakalı yanlış bir kullanımı da testimizi düzgün bir şekilde gerçekleştiremediğimizde farkedebiliyoruz:Metodumuz çok fazla iş yapıyor. Hem mail server’a bağlanıp mail okuyor hem de okunmuş ve okunmamış mail sayılarını hesaplayarak rapor hazırlıyor. Aslında metodumuz Single Responsibility Prensibine ve Dependency Inversion Prensibine uymuyor bu yüzden de test edilmesi oldukça zor.

Single Responsibility Prensibinin Uygulanması

Biraz refactoring yapıyoruz.Öncelikle kodun Single Responsibility prensibine uyması için sorumluklarını farklı sınıflara ayıralım. Aşağıdaki gibi kodu ve testi tekrar yazalım.

        [Test]
        public void MailRaporuOlustur()
        {
            MailRaporuOlusturucu mailRaporuOlusturucu = new MailRaporuOlusturucu(new MailOkuyucu());
            MailRaporu rapor = mailRaporuOlusturucu.RaporOlustur();
            Assert.AreEqual(153,rapor.OkunmusMailSayisi);
            Assert.AreEqual(5,rapor.OkunmamisMailSayisi);
        }
    public class MailRaporuOlusturucu
    {
        private readonly MailOkuyucu mailOkuyucu;
        public const string KULLANICI_ADI = "Cihat";
        public const string SIFRE = "1111";

        public MailRaporuOlusturucu(MailOkuyucu mailOkuyucu)
        {
            this.mailOkuyucu = mailOkuyucu;
        }

        public MailRaporu RaporOlustur()
        {
            int okunmusMailSayisi = 0, OkunmamisMailSayisi = 0;
            mailOkuyucu.Baglan(KULLANICI_ADI,SIFRE);
            IList<Mail> mailListesi = mailOkuyucu.ButunMailleriGetir();
            mailOkuyucu.BaglantiyiKapat();
            for (int i = 0; i < mailListesi.Count; i++)
            {
                Mail mail = mailListesi[i];
                if (mail.Okunmus)
                    okunmusMailSayisi++;
                else
                    OkunmamisMailSayisi++;
            }
            return new MailRaporu(okunmusMailSayisi, OkunmamisMailSayisi);
        }
    }
    public class MailOkuyucu
    {
        public void Baglan(string kullaniciAdi, string sifre)
        {
            //mail sunucusuna kullanıcı adı şifre kullanarak bağlanıyor.
        }

        public IList<Mail> ButunMailleriGetir()
        {
            List<Mail> mails = new List<Mail>();
            //Gerçek mail sunucusuna bağlanıp mail sayılarını hesaplıyor
            //....
            return mails;
        }

        public void BaglantiyiKapat()
        {
            //bağlantı kapatılıyor
        }
    }

Evet kod yavaş yavaş adama benzemeye başladı :) Kodu sorumluluklarına göre farklı sınıflara ayırdık artık herkes kendi işini yapıyor. Şimdi tekrar düşünelim en üstteki MailSayisi testimiz çalışacak mı?Hayır çünkü sınıflar değişti fakat MailOkuyucu sınıfının ButunMailleriGetir metodu çağırıldığında yine gerçek sunucuya bağlandığı için testimiz yine başarısız olacaktır.Ayrıca bağlantı açıldı mı,kapandı mı bunu test edemiyoruz yani hala düzgün test edemiyoruz.

Dependency Inversion Prensibinin Uygulanması

Bunun için ikinci aşama olarak Dependency Inversion prensibine uygun hale getireceğiz.
Hatırlamak için tekrarlayalım:”Yüksek seviyeli sınıflar alt seviyeli sınıflara bağımlı olmamalıdır”. Aralarındaki arayüzlere(interface ya da abstract sınıflar)  bağımlı olmalıdır. Bu yüzden kodumuzu biraz daha değiştirip aşağıdaki hale getiriyoruz.

        [Test]
        public void MailRaporuOlustur()
        {
            MailRaporuOlusturucu mailRaporuOlusturucu = new MailRaporuOlusturucu(new MailOkuyucu());
            MailRaporu rapor = mailRaporuOlusturucu.RaporOlustur();
            Assert.AreEqual(153,rapor.OkunmusMailSayisi);
            Assert.AreEqual(5,rapor.OkunmamisMailSayisi);

        }
    public class MailRaporuOlusturucu
    {
        private readonly IMailOkuyucu mailOkuyucu;
        public const string KULLANICI_ADI = "Cihat";
        public const string SIFRE = "1111";

        public MailRaporuOlusturucu(IMailOkuyucu mailOkuyucu)
        {
            this.mailOkuyucu = mailOkuyucu;
        }

        public MailRaporu RaporOlustur()
        {
            int okunmusMailSayisi = 0, OkunmamisMailSayisi = 0;
            mailOkuyucu.Baglan(KULLANICI_ADI,SIFRE);
            IList<Mail> mailListesi = mailOkuyucu.ButunMailleriGetir();
            mailOkuyucu.BaglantiyiKapat();
            for (int i = 0; i < mailListesi.Count; i++)
            {
                Mail mail = mailListesi[i];
                if (mail.Okunmus)
                    okunmusMailSayisi++;
                else
                    OkunmamisMailSayisi++;
            }
            return new MailRaporu(okunmusMailSayisi, OkunmamisMailSayisi);
        }
    }


    public interface IMailOkuyucu
    {
        void Baglan(string kullaniciAdi, string sifre);
        IList<Mail> ButunMailleriGetir();
        void BaglantiyiKapat();
    }

    public class MailOkuyucu : IMailOkuyucu
    {
        public void Baglan(string kullaniciAdi, string sifre)
        {
            //mail sunucusuna kullanıcı adı şifre kullanarak bağlanıyor.
        }

        public IList<Mail> ButunMailleriGetir()
        {
            List<Mail> mails = new List<Mail>();
            //Gerçek mail sunucusuna bağlanıp mail sayılarını hesaplıyor
            //....
            return mails;
        }

        public void BaglantiyiKapat()
        {
            //bağlantı kapatılıyor
        }
    }

Şimdi yukarıda gördüğünüz gibi artık MailRaporuOlusturucu sınıfı gerçek sınıfa değil de bir interface’e bağlı.O arayüzü uygulayan(implementation) herhangi bir sınıfı sisteme verdiğimizde kodumuz çalışmaya devam edecektir.Tasarım olarak gayet iyi bir noktaya geldik. Fakat hala test edemiyoruz çünkü dikkat edin test metodunun içinde MailRaporuOlusturucu sınıfının yapıcısına(constructor) IMailOkuyucu arayüzünü uygulayan gerçek MailOkuyucu sınıfını verdiğimiz için aynen gerçek sunucuya bağlanmaya devam edecek testimiz yine bize istemediğimiz sonuçları vermeye devam edecek. Ayrıca hala bağlantı açılıp kapandımı testlerimizde kontrol edemiyoruz.

Stubs

Şimdi kodumuzu buraya kadar iyileştirdikten sonra test edebilmemiz aslında kolaylaştı bunun için uygulayabileceğimiz ilk tekniklerden biri Stub nesneler kullanmak. Şimdi Stub nedir kısaca şöyle açıklayalım: Yukarıdaki MailRaporuOlusturucu sınıfının yapıcısına test amaçlı aynı interface’i uygulayan bir sınıf oluşturup veriyoruz ve bu sınıf üzerinden istediğimiz sonuçları döndürüyoruz. Şimdi Stub nesne kullanarak aşağıdaki testimizi tekrar yazalım.

    class MailOkuyucuStub:IMailOkuyucu
    {
        private List<Mail> mailListesi = new List<Mail>();
        public string BaglanilanSifre { get; set; }
        public string BaglanilanKullaniciAdi { get; set; }
        public bool BaglantiKapatildi { get; set; }

        public List<Mail> MailListesi
        {
            get { return mailListesi; }
        }

        public void Baglan(string kullaniciAdi, string sifre)
        {
            BaglanilanKullaniciAdi = kullaniciAdi;
            BaglanilanSifre = sifre;
        }
        

        public IList<Mail> ButunMailleriGetir()
        {
            return mailListesi;
        }

        public void BaglantiyiKapat()
        {
            BaglantiKapatildi = true;
        }
    }

    [TestFixture]
    public class MailRaporuOlusturucuTest
    {
        [Test]

        public void MailCount()
        {
            MailOkuyucuStub okuyucuStub =new MailOkuyucuStub();
            for(int i=0;i<153;i++)
            {
                Mail mail = new Mail();
                mail.Okunmus = true;
                okuyucuStub.MailListesi.Add(mail);
            }

            for(int i=0;i<5;i++)
            {
                Mail mail = new Mail();
                mail.Okunmus = false;
                okuyucuStub.MailListesi.Add(mail);
            }


            MailRaporuOlusturucu mailRaporuOlusturucu = new MailRaporuOlusturucu(okuyucuStub);
            MailRaporu rapor = mailRaporuOlusturucu.RaporOlustur();
            Assert.AreEqual(153, rapor.OkunmusMailSayisi);
            Assert.AreEqual(5, rapor.OkunmamisMailSayisi);
            Assert.AreEqual(MailRaporuOlusturucu.KULLANICI_ADI,okuyucuStub.BaglanilanKullaniciAdi);
            Assert.AreEqual(MailRaporuOlusturucu.SIFRE,okuyucuStub.BaglanilanSifre);
            Assert.AreEqual(true,okuyucuStub.BaglantiKapatildi);
        }
    }

Gördüğünüz gibi test ortamında aynı arayüzü uygulayan test amaçlı bir Stub nesne oluşturduk.Bu nesneye test esnasında 153 adet okunmuş mail,5 tane de okunmamış mail ekledik. Artık kontrol gerçek mail sunucusunun elinde değil bizim elimizde.Böylece istediğimiz sayıda mail dödürebiliyoruz.Ayrıca Stub nesnesi içinde bağlanmak için gelen kullanıcı adı ve şifreyi tutarak test esnasında düzgün parametrelerin gelip gelmediğini kontrol ettik.Bağlantıyı kapatan metodun çağırılıp çağrılmadığını da bu teknikle stub içinde saklayıp test sırasında kontrol ettik.Bağlantı kapatma metodu çağırılmışmı onu da bu teknikle stub içinde saklatıp test sırasında kontrol ettik.

Mock Objects

Şimdi aynı testleri Mock Objects tekniği kullanarak test edelim. Öncelikle Mock Objects nedir kısaca anlatalım. Mock nesneler test sırasında aynı Stublar gibi nesnelerin bizim istediğimiz değerleri döndürülmesini ve doğru metodlar doğru parametreler ile çağırılmış mı onu kontrol eder.Fakat test ediliş şekilleri farklıdır.Mock objelere çağırılmasını beklediği metodları ve parametreleri veririz ardından düzgün çağırılmışmı mock objelerin kendisi kontrol eder. Stub nesneler kullandığımızda hatırlayın bunu Assert.AreEquels metodları ile kendimiz yapıyorduk. Mock objeler ise bunu kendi içlerinde kontrol ederler.

Tabi elle yazmak oldukça zahmetli bir iş şuana kadar hiç el ile mock yazmadım fakat herhangi bir mock object framework kullanmaya başlamadan önce el ile kendi yaptığımız mock nesneler ile bunun nasıl yapıldığını görmeniz bu frameworklerin nasıl işlediğini ve neler yaptığınızı anlamanız açısından iyi olacaktır.

    class MockMailOkuyucu:IMailOkuyucu
    {
        private string beklenenKullaniciAdi;
        private string beklenenSifre;
        private bool baglantiKapatildi;
        private bool beklenenBaglantiKapatildi;
        public List<Mail> MailListesi = new List<Mail>();

        public void BeklenenBaglan(string kullaniciAdi, string sifre)
        {
            beklenenKullaniciAdi = kullaniciAdi;
            beklenenSifre = sifre;
        }

        public void BaglantiKapatildiCagirilmaliMi(bool deger)
        {
            beklenenBaglantiKapatildi = deger;
        }


        public void Baglan(string kullaniciAdi, string sifre)
        {
            Assert.AreEqual(beklenenKullaniciAdi, kullaniciAdi);
            Assert.AreEqual(beklenenSifre, sifre);
        }

        public IList<Mail> ButunMailleriGetir()
        {
            return MailListesi;
        }

        public void BaglantiyiKapat()
        {
            baglantiKapatildi = true;
        }

        public void KontrolEt()
        {
            Assert.AreEqual(beklenenBaglantiKapatildi,baglantiKapatildi);
        }
    }
    [TestFixture]
    public class MailRaporuOlusturucuMockTest
    {
        [Test]
        public void MailCount()
        {
            MockMailOkuyucu mockMailOkuyucu = new MockMailOkuyucu();
            for (int i = 0; i < 153; i++)

            {
                Mail mail = new Mail();
                mail.Okunmus = true;
                mockMailOkuyucu.MailListesi.Add(mail);
            }

            for (int i = 0; i < 5; i++)
            {
                Mail mail = new Mail();
                mail.Okunmus = false;
                mockMailOkuyucu.MailListesi.Add(mail);
            }
            mockMailOkuyucu.BeklenenBaglan(MailRaporuOlusturucu.KULLANICI_ADI,MailRaporuOlusturucu.SIFRE);
            mockMailOkuyucu.BaglantiKapatildiCagirilmaliMi(true);

            MailRaporuOlusturucu mailRaporuOlusturucu = new MailRaporuOlusturucu(mockMailOkuyucu);
            MailRaporu rapor = mailRaporuOlusturucu.RaporOlustur();
            Assert.AreEqual(153, rapor.OkunmusMailSayisi);
            Assert.AreEqual(5, rapor.OkunmamisMailSayisi);
            mockMailOkuyucu.KontrolEt();
        }
    }

Yukarıda Stub ile yazdığımız aynı testi el ile yazdığımız mock ile aynı şekilde test ettik. Dikkat edin Mock objeye Baglan metodunun hangi parametreler ile çağırılması gerektiğini söyledik ardından kapat çağırılmalı mı onu söyledik ve en sonunda bunun mock objenin kendi KontrolEt metodu ile kontrol ettik.Aslında Mock Objects Frameworklerin yaptığıda bu sınıfları çalışma anında bizim kod yazmamıza gerek kalmadan otomatik olarak oluşturmak.

Mock Object Framework İle Test Etme

En sona kaldı fakat kendi adıma en çok kullandığım yöntem olan Mock object framework ile kullanarak aynı testi tekrar yazıyoruz.Bu arada birsürü bu tarz mock nesneler oluşturan hem Java hem .NET için framework mevcut.Ben .NET için aşağıda kullandığım Rhino Mocks kütüphanesini kullanıyorum.Java içinde aşağı yukarı aynı yapıda olan EasyMock kullanıyorum.

        [Test]
        public void MailCountMockFramework()
        {
            IList<Mail> mailListesi = new List<Mail>();
            
            for (int i = 0; i < 153; i++)
            {
                Mail mail = new Mail();
                mail.Okunmus = true;
                mailListesi.Add(mail);
            }

            for (int i = 0; i < 5; i++)
            {
                Mail mail = new Mail();
                mail.Okunmus = false;
                mailListesi.Add(mail);
            }

            MockRepository mockRepository =new MockRepository();
            IMailOkuyucu mockMailOkuyucu = mockRepository.StrictMock<IMailOkuyucu>();

            mockMailOkuyucu.Baglan(MailRaporuOlusturucu.KULLANICI_ADI, MailRaporuOlusturucu.SIFRE);
            mockMailOkuyucu.BaglantiyiKapat();
            Expect.Call(mockMailOkuyucu.ButunMailleriGetir()).Return(mailListesi);
            mockRepository.ReplayAll();


            MailRaporuOlusturucu mailRaporuOlusturucu = new MailRaporuOlusturucu(mockMailOkuyucu);
            MailRaporu rapor = mailRaporuOlusturucu.RaporOlustur();
            Assert.AreEqual(153, rapor.OkunmusMailSayisi);
            Assert.AreEqual(5, rapor.OkunmamisMailSayisi);
            mockRepository.VerifyAll();
        }

Gördüğünüz gibi artık el ile yaptığımız mock nesnesini framework bizim için oluşturdu. Bunu çalışma anında proxy nesneler oluşturarak bizim el ile yazdığımız mock nesnesine benzer nesneler oluşturarak yapıyor. Zaten test sırasında gördüğünüz gibi mockRepository.ReplayAll(); satırına kadar hangi metodların hangi parametreler ile çalışması gerektiğini söyledik. Ardından Expect.Call(mockMailOkuyucu.ButunMailleriGetir()).Return(mailListesi); satırı ile de ButunMailleriGetir metodu çağırıldığında hangi listenin dönmesi gerektiğini Frameworke söyledik. ReplayAll() metodu ile Framework bizim beklediğimiz ve dönmesi gerektiğimiz şeyleri hafızasına aldı ardından mockRepository.VerifyAll(); satırında daha önceden hafızasına aldığı şartların yerine getirilip getirilmediğini kontrol ediyor.

Test etmesi zor olan kısımları Mock ve Stub nesneler ile nasıl test edebildiğimizi gördük.Aslında burada Test Driven Development’ın en güzel yanlarından biri ortaya çıkıyor. Burda Mocks ve Stubs nedir örnek olsun diye kodu önce test edilemeyen şekliyle yazdım. Fakat normalde TDD uygularken önce test kodu yazdığınız için tasarımınız Single Responsibility ve Dependency Inversion prensibine uymak zorunda kalıyor. Bu yüzden sizi daha düzgün tasarımı olan gerçek sınıflara değilde arayüzlere bağımlı olan kod yazmanıza zorluyor. Bunlarda nesneye yönelik programlama için oldukça önemli kavramlar.Ayrıca diğer güzel yanı dikkat ederseniz gerçek mail sunucusuna bağlantı yapan kodu yazmadan rapor oluşturan kodu yazdım. Yani kodu yazmak için alt seviyeli database,network.. gibi şeylerin hazır olmasınada gerek kalmıyor.

Yorumsuz : En İyi Programcı Kim?

The people who are best at programming are the people who realize how small their brains are. They are humble. The people who are the worst at programming are the people who refuse to accept the fact that their brains aren’t equal to the task. Their egos keep them from being great programmers.

Steve Mcconnell, Code Complete 2

Programlamada en iyi olan insanalar beyinlerinin ne kadar küçük olduğunu bilen alçak gönüllü insanlardır. Programlama da en kötü olan insanlar beyinlerinin küçük olduğunu inkar eden insanlardır. Egoları onların mükemmel programcı olmalarını engeller. Gerçekten aydınlanmaya giden yol ne kadar az bildiğimizi kabul etmekten geçiyor.

Nhibernate-3

Merhaba bu yazımızda Nhibernate ile veritabanı sorgulama metodlarını inceleyeğiz.
Hql
Hibernate Query Language(hql) bildiğimiz ansi-sql’e çok benzeyen hibernate için özelleştirilmiş bir sorgulama dilidir.
Hemen bir örnek yapalım:

OkulDAONHibernate _dao = new OkulDAONHibernate();
IList<Ogrenci> liste= _dao.GetOgrenciByAdSoyadHQL("İsmail", "Koç");

...............
public IList<Ogrenci> GetOgrenciByAdSoyadHQL(string strAd,string strSoyad)
        {
            ISession session = NHibernateHttpModule.CurrentSession;
            return session.CreateQuery("select from Ogrenci o where o.Ad=:AD and o.Soyad=:SOYAD")
                .SetString("AD", strAd)
                .SetString("SOYAD", strSoyad)
                .List<Ogrenci>();
        }

Sql
İlla da Sql! Sql’den vazgeçmem diyenler için:

OkulDAONHibernate _dao = new OkulDAONHibernate();
IList<Ogrenci> liste= _dao.GetOgrenciByAdSoyadSQL("İsmail", "Koç");

............................
    public IList<Ogrenci> GetOgrenciByAdSoyadSQL(string strAd, string strSoyad)
        {
            ISession session = NHibernateHttpModule.CurrentSession;
            return session.CreateSQLQuery("select * from OGRENCI  where Ad=:AD and Soyad=:SOYAD")
                .AddEntity(typeof(Ogrenci))
                .SetString("AD", strAd)
                .SetString("SOYAD", strSoyad)
                .List<Ogrenci>();
        }

Hemen iki fark göze çarpmalı
=>CreateQuery metodu yerine CreateSqlQuery metodunu kullandık.
=>CreateSqlQuery metoduna fazladan AddEntity metodunu ekledik.Takdir edersinizki Nhibernate sql cümlesi içerisinde gönderdiğiniz tablo adı/adlarının hangi sınıfa karşı geldiğini bilmez.Bu yüzden sorguda kullanılacak sınıfın Ogrenci olduğunu belirtiyoruz.
“Ben bu yöntemi ‘select * from Ogrenci’ şeklinde değil de “select ad from Ogrenci’ şeklinde kullanmak istiyorum” diyenler olabilir ama bu şekilde kullanım geçersizdir.Zira tablodaki satır tamamen geldiğinde bir sınıfa karşılık gelir.”Sadece iki kolonu çeksin ve bunları da nesnenin o iki propety’sine set etsin” diyebiliriz ama Nhibernate bu yöntemi desteklemiyor.

Expressions
Expression kullanma yöntemi bu üç yöntemden benim tercih ettiğim yöntem…İzlenebilir olması ve içerisinde string ifadeler bulanmaması(select * from ,inner join….) tercih edilmesinin sebeplerinden…
Hemen örneklerimize başlayalım

1)Soyadı “Koç” olan öğrencileri bulalım.

     ISession session = NHibernateHttpModule.CurrentSession;
     return   session.CreateCriteria(typeof(Ogrenci))
             .Add(Expression.Eq("Soyad","Koç"))
             .List<Ogrenci>();

Gördüğünüz gibi burda Expression sınıfını kullanıyoruz.Bu sınıf içinde işimize yarayan bir çok metod bulunuyor.(Expression.Gt,Ge,Lt,Le,In,IsEmpty,Like,InsensitiveLike…).Hemen aklıma gelmişken hatırlatayım veritabanı olarak oracle kullanıyorsak oracle case sensitive olduğu için expressionlar içine verdiğiniz değerlere dikkat etmeliyiz.”KOÇ” ile “koç” biribirinden farklı değelerdir.

2)Adında “a” harfi geçen öğrencileri soyadlarına göre azalan sırada sıralayalım.

ISession session = NHibernateHttpModule.CurrentSession;
      return   session.CreateCriteria(typeof(Ogrenci))
<div style="display: none"><a href='http://professionalessaywriter.net/'>professional college essay writers</a></div>                .Add(Expression.Like("Ad","%a%"))
                .AddOrder(Order.Desc("Soyad"))
                .List<Ogrenci>();

3)Adı “ismail” ya da “taner” olan öğrencileri soyadlarına göre artan sırada sıralayalım.

	ISession session = NHibernateHttpModule.CurrentSession;
      return   session.CreateCriteria(typeof(Ogrenci))
                .Add(
                    Expression.Or(
                                    Expression.Eq("Ad","İsmail"),
                                    Expression.Eq("Ad","Taner")
                                 )
                     )
                .AddOrder(Order.Asc("Soyad"))
                .List<Ogrenci>();

4)Adı “İsmail” ve soyadı alanı boş olmayan öğrencileri getirelim.

ISession session = NHibernateHttpModule.CurrentSession;
      return   session.CreateCriteria(typeof(Ogrenci))
                .Add(
                       Expression.And(
                                             Expression.Eq("Ad","İsmail"),
                                             Expression.IsNotEmpty("Soyad")
                                          )
                     )
                .List<Ogrenci>();

5)Adı “ismail” olan soyadı “koç” yada “kılıç” olan öğrencileri getirelim.

ISession session = NHibernateHttpModule.CurrentSession;
      return   session.CreateCriteria(typeof(Ogrenci))
                 .Add(Expression.Eq("Ad","İsmail"))
                 .Add(
                      Expression.Or(
                                    Expression.Eq("Soyad","Koç"),
                                    Expression.Eq("Soyad","kılıç")
                                )
                     )
                .List<Ogrenci>();

Example
Diğer bir yöntemimiz de örnek nesne kullanıp sorgulama yapma yöntemidir.

1)Adı “İsmail” olan öğrencileri çekelim.

Ogrenci ogr=new Ogrenci();
      ogr.Ad = "ismail";
           ...............
     ISession session = NHibernateHttpModule.CurrentSession;
     return session.CreateCriteria(typeof(Ogrenci))
                .Add(Example.Create(ogr))
                .List<Ogrenci>();

2)Sınıfı 9B(id=7) olan öğrencileri example kullanarak bulalım.

ISession session = NHibernateHttpModule.CurrentSession;
      Sinif snf = session.CreateCriteria(typeof(Sinif))
            .Add(Expression.Eq("SinifId",7))
           .List<Sinif>()[0];
         ..............
      Ogrenci ogr=new Ogrenci();
      ogr.Sinif = snf;
         ..............
      return session.CreateCriteria(typeof(Ogrenci))
            .Add(Example.Create(ogr))
                 .CreateCriteria("Sinif")
                 .Add(Example.Create(ogr.Sinif))
             .List<Ogrenci>();

5)Önce 7B sınıfını getirdik.
8)Sonra bir öğrenci nesnesi oluşturup “Sinif” property’sine getirdiğimiz snf nesnesini atadık.
10)Daha sonra Ogrenci tipinden bir criteria oluşturduk.
12)Sorgumuzun “Sinif ilişkisi” üzerinden olacağını belirttik.
Yani iç içe iki example vermiş olduk.

Bu örnekleri bu şekilde uzatabiliriz.Bir sonraki yazımızda having,count,sum gibi metodları ve subcriteria sınıfını inceleyeğiz.

Nhibernate-2

Yazımızın ikinci bölümünde Nhibernate’in derinliklerine doğru yol alalım.Uzunca girizgahlara hiç gerek yok.Hemen başlayalım.

Load(),Get()
Id’sini bildiğimiz nesneleri çekmek için kullanılır.Criteria oluşturmaya gerek yoktur.

Ogrenci ogr=new Ogrenci();
ogr=(Ogrenci)session.Load(typeof(Ogrenci),242);
ogr=(Ogrenci)session.Get(typeof(Ogrenci),242);

Birinci kullanımda nesnenin veritabanında karşılığı yoksa exception fırlatır.Get metodunu kullandığımızda nesnenin veritabanında karşılığı yoksa metod null değeri döndürür.

Lazy
Lazy kavramına daha sonra değinmeyi planlıyordum ama sonraki örneklerde bolca lazım olacağı için anlaşılması gereken bir kavram.Nhibernate’in işinin aslında nesneler(tablolar) arası ilişkileri yönetmek olduğundan bahsetmiştik.Bir önceki yazının son kısmında yaptığımız örnekte veritabanından bir Okul nesnesi çekmiş onun Siniflar listesinin içine dallanmıştık.Şimdi okul sınfıını çektiğimizde onun yavru kayıtlarını o kayıtların da yavru kayıtlarını çektiğimizi hayal edin.İyi ilişkilendirimiş bir veritabanımız varsa nerdeyse tüm veritabanını çekmeye kalkıyoruz demektir.Öyleyse bu işleme bir yerde dur demeliyiz.Burda “lazy” devreye giriyor.Lazy=true ifadesinin ana kaydın collection’ında kullandığımızda “Bu collection’ı doldurma.İhtiyacım olduğunda getir” demiş oluyoruz.Peki nhibernate bizim bu listeye ihtiyacımız olduğundan nasıl haberdar oluyor:Kod satırında nesneyi yazıp o nesnenin bahsi geçen listesine ulaştığımız an Nhibernate o listeyi bizim için dolduruyor.Aşağıdaki sqlserverprofiler aracı ile çalışan sql cümlelerini inceleyelim.

=>Lazy=false değeri set edilmediği durumda

IList<Okul> liste= _dao.TumOkullariGetir();


Gördüğünüz gibi hem Okul sorgusu hem de Sinif sorgusu çalıştı.

=>Lazy=true değeri set edilmediği durumda

IList<Okul> liste= _dao.TumOkullariGetir();

Sadece okul sorgusu çalıştı.
Gelen sonucu watch edip “Sınıflar” listesini açtığımızda


GetAllOkul metedomuzu tekrar gözden geçirelim.Açtığımız session’ı kapatmadık.Şu şekilde olmalıydı.

     public IList<Okul> GetAllOkul()
        {
            ISession session = _sessionFactory.OpenSession();
            ICriteria criteria = session.CreateCriteria(typeof(Okul));
            IList<Okul> liste = criteria.List<Okul>();
            <em>session.close(); </em>
            return liste;  
        }

Kodumuzu bu şekilde değiştirdikten sonra presenter sınıfımızdaki kodumuza geri dönelim.

IList<Okul> liste= _dao.GetAllOkul();
Sinif sinif=liste[0].Siniflar[0];

Üçüncü satıra dikkat edelim.Gelen okulların ilkinin ilk sınıfını almaya çalışıyoruz.Bu arada lazy=true ve session kapatıldı.

Hatırlayacağınız gibi lazy=true ifadesi bize listeye ihtiyacımız olduğu zaman listeyi gidip dolduruyordu.GetAllOkul metodundan çıkıldığı zaman session’ı kapattık.Çok daha sonra Siniflar listesine erişmek istediğimizde açık session olmadığı hatasını aldık.Öyleyse session’ımızın sürekli açık olması gerekiyor.Sesion’ı ve sessionfactory’yi bir yerlerde saklamak gerekiyor.Bunun için bir HTTPModule kullanıyoruz.Bunun için aşağıdaki gibi iki yapı kullanıyoruz.

Önce OKULDAO sınıfının yapıcısında yazdığımız Nhibernate konfigurasyonunu kaldırıyoruz.Çünkü bu nesneden instance alındığında aşağıdaki kod bloğu çalışıyor.Her seferde sessionfactory oluşturuluyor.Bu çok maliyetli bir yaklaşım.Bunun yerine sessionfactory bir defa oluşturulup pekala ASP.Net session’da saklanabilir.

private static ISessionFactory _sessionFactory;
public OkulDAONHibernate()
{
     Configuration config =new Configuration().Configure();
     _sessionFactory = config.BuildSessionFactory();
}

İki sınıfımız bize bu konuda yardımcı olacak: SessionHelper ve NhibernateHttpModule.

public class SessionHelper
    {
    private static ISessionFactory _sessionFactory = null;
        private static ISessionFactory SessionFactory
        {
            get
            {
                if (_sessionFactory == null)
                {
                    Configuration config = new Configuration().Configure();
                    _sessionFactory = config.BuildSessionFactory();
                    if (_sessionFactory == null)
                        throw new InvalidOperationException("Could not build SessionFactory");
                }
                return _sessionFactory;
            }
        }
        public static ISession OpenSession()
        {
            ISession session;
            session = SessionFactory.OpenSession();
            if (session == null)
                throw new InvalidOperationException("Cannot open session");
            return session;
        }
    }

Gördüğünüz gibi _SessionFactory bir kere oluşturulup static bir değişkene atılıyor.
NhibernateHttpModule sınıfı çok önemli o yüzden ayrıntılı incelemenizi tavsiye ederim.

  public class NHibernateHttpModule : IHttpModule
     {
         public const string KEY ="_TheSession_";
         private static ISession _session;
 
         private void context_BeginRequest(object sender, EventArgs e)
         {
             HttpApplication application = (HttpApplication)sender;
             HttpContext context = application.Context;
             context.Items[KEY] = SessionHelper.OpenSession();
         }
 
         private void context_EndRequest(object sender, EventArgs e)
         {
             HttpApplication application = (HttpApplication)sender;
             HttpContext context = application.Context;
 
             ISession session = context.Items[KEY] as ISession;
             if (session != null &amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp; session.IsOpen)
             {
                 try
                 {
                     session.Flush();
                     session.Close();
                 }
                 catch { }
             }
             context.Items[KEY] = null;
         }
 
         public static ISession CurrentSession
         {
             get
             {
                 if (HttpContext.Current == null)
                 {
                     if (_session != null)
                         return _session;
 
                     _session = SessionHelper.OpenSession();
                     return _session;
                 }
                 HttpContext currentContext = HttpContext.Current;
                 ISession session = currentContext.Items[KEY] as ISession;
                 if (session == null)
                 {
                     session = SessionHelper.OpenSession();
                     currentContext.Items[KEY] = session;
                 }
                 return session;
             }
         }
         #region IHttpModule Members 
         public void Init(HttpApplication context)
         {
             context.BeginRequest += new EventHandler(context_BeginRequest);
             context.EndRequest += new EventHandler(context_EndRequest);
         }

59.-60.) Bu iki satır IHttpModule sınıfınından implement ettiğimiz metodlar.Böylece “open session per request” yapımızı kurmuş olacağız.Her istek geldiğinde (11.) SessionHelper yardımı ile Sessionfactory üzerinden bir session açıyoruz.İstek sonlandığında (24.) session’ımızı flush ediyoruz.Böylece arada kalmış, veritabaınına güncellenmemiş nesnelerimiz kalmıyor.
Bu yapının web uygulamamız tarafından kullanılabilmesi için webconfig ayarlarını aşağıdaki gibi değiştiriyoruz.

<system.webServer>	
    <modules>
      <add type="SanalOkul.DAO.NHibernateHttpModule,SanalOkul.DAO" name="NhibernateHttpModule"/>
   </modules>

Şimdi OkulDAO sınıfımızın son haline göz atalım.

  public IList<Okul> GetAllOkul()
        {
            ISession session = NHibernateHttpModule.CurrentSession;
            ICriteria criteria = session.CreateCriteria(typeof(Okul));
            IList<Okul> liste = criteria.List<Okul>();
            return liste;
        }

Gördüğünüz gibi artık sessionfactory oluşturma session açma,kapatma işlemleriyle biz uğraşmıyoruz.

save(),update(),SaveorUpdate(),SaveorUpdateCopy(),delete()

Save metodunun kullanımına örnek

Ogrenci ogr=new Ogrenci();
ogr.Ad = "taner";
ogr.Soyad = "bozdemir";
session.Save(ogr);
session.Flush();
session.Refresh(ogr);

5.)Nesneyi session’ımıza yolluyoruz.Henüz id alanı set edilmedi.
6.)Session’in içinde yer alan nesne(ler) veritabanına yazılıyor.Burada dikkat etmemiz gereken bir nokta var.Flush metodu sadece ogr nesnesi için çalışmaz.O anda session’da yer alan ve değişikliğe uğramış tüm nesneleri veritabanında güncellemeye çalışır.Daha önce de belirttiğimiz gibi Nhibernate nesneleri id alanalrından tanır.Load ettiği nesneleri session kapanana kadar takip eder.Isdirty diye bir alan üzerinden nesnenin değişikliğe uğrayıp uğramadığını takip eder.
7.)Nesnenin son halini veritabanından alır.veritabanında trigger türü veri üzerinde değişiklik yapacak yapılar bulunuyorsa nesnesinin son halini almak için birebirdir.Şahsen veritabanında stored procedure,function,trigger türü yapıların kullanılmasını pek benimsemiyorum.Bu tür işlemlerin business logic içerisinde gerçekleştirilmesi taraftarıyım.

Update metodunun kullanımına örnek

Ogrenci ogr=new Ogrenci();
session.Load(ogr,242);
ogr.Soyad = "bozdemir";
session.Update(ogr);
session.Flush();

5.)Bu satıra aslında gerek yok çünkü hemen alt satırdaki session.flush() metodu değişen nesneleri belirleyip bunları veritabanında güncelleyecektir.

SaveorUpdate ve SaveorUpdateCopy metodları save ve update metodlarının yerine kullanılır.Eğer nesnenin veritabanında karşılığı varsa(persistent) Nhibernate bu nesneyi günceller.Eğer yeni bir kayıt(Transient) ise nesneyi veri tabanına kaydeder.

Ogrenci ogr=new Ogrenci();
session.Load(ogr,242);
ogr.Soyad = "bozdemir";
session.SaveOrUpdateCopy(ogr);
session.Flush();

5.)242 id’li bir kayıt veritabanında varsa güncellenir,kayıt yoksa yeni bir kayıt olarak veritabanına işlenir.SaveorUpdateCopy, SaveorUpdate metodundan farklı olarak kaydettiği nesnenin bir kopyasını geri döndürür.Ayrıca Update ve SaveorUpdate kullanıldığında aynı id değerini taşıyan başka bir nesne session içerisinde yer alıyorsa “different object with the same identifier value” hatası alırız.SaveorUpdateCopy metodu yeni oluşturlan nesnenin tüm durumunu zaten session içerisinde yer alan aynı id’ye sahip nesnenin üzerine giydirir böylece tek nesne haline getirir.Bu yüzden save/update işlemlerinizde SaveorUpdateCopy metodunu kullanmanızı tavsiye ederim.Bu metodun Hibernate’deki karşılığı da bildiğim kadarıyla “merge” metodur.

Şimdi de Asp.net Session ile Nhibernate’i birlikte kullanalım.Presenter sınıfımızı bir anlığına aradan çıkardığımızı,view’in dao’ya direk eriştiğini varsayalım örneğin daha kolay anlaşılabilmesi için…

public partial class _Default : System.Web.UI.Page
{
    protected void Page_Load(object sender, EventArgs e)
    {
        if (!IsPostBack)
        {
           OkulDAONHibernate _dao = new OkulDAONHibernate();
           Okul okl = _dao.GetById(1);
           okl.Adres += " Türkiye Dünya";
          _dao.Update(okl);
           Session["okl"] = okl;
         }
     }
    protected void Button1_Click(object sender, EventArgs e)
    {
       OkulDAONHibernate _dao=new OkulDAONHibernate();
       Okul okl = (Okul) Session["okl"];
       Sinif snf= okl.Siniflar[0];
       snf.SinifAdi = "11D";
      _dao.Update(okl);
     }
}

8.)Id’si 1 olan okulu getiriyoruz.
9.-10.)Adres alanını güncelliyoruz.
11.)Nesneyi Asp.Net Session’a atıyoruz.
17.)Buton eventi altında nesneyi Asp.Net Session’ınından geri alıyoruz.
18.)Siniflar listesine ulaşıp ilk sınıfı alıyoruz.
19.-20.)O sınıfın adını “11D” olarak güncelliyoruz.

Peki bu kod düzgün çalışır mı?Hemen söyleyelim çalışmaz.
=>Page_Load eventi altında okul nesnemizi veritabanından çekiyoruz.(buraya dikkat! Siniflar listesi lazy=true)
=>Okul nesnemizin adresini güncelliyoruz.
=>Nesneyi Asp.Net Session’a atıyoruz.
=>PageLoad eventi bitiyor ve NhibernateHttpModule içindeki context_EndRequest metodu çalışıyor.
=>Buton eventi başlıyor context_BeginRequest metodu çalışıyor ve yeni bir session açılıyor.
=>18.satırda kapanan session’a ait nesnemizi geri alıyoruz.
=>19.satırda nesnenin lazy olan listesine erişmek isityoruz.Nhibernate devreye girip listeyi bizim için çekmeye kalkıyor ama bu nesnenin listesi kapanan bir session’a ait.Vee çok sevdiğimiz hatamız gene karşımızda: failed to lazily initialize a collection – no session

Bu durumda elimizde üç seçenek var:
=>Listeyi lazy=false yapmak ama bu değişkeni kontrollü kullanmak lazım zira çok büyük listeler performansı dibe çeker.
=>Page Load eventi altında değiştirmek istediğimiz sınıfın ait olduğu okulu değil de “Sinif” nesnesinin kendisini Asp.Net Session içine gömüp aşağıda gerekli değişikliği yapıp güncelleme yaparız.
=>Okul nesnesini Page Load eventi altında session’a atıp Buton event’i altında erişerek o nesneyi id’siyle yeniden veritabanından getirterek sinifları üzerinde işlem yapmak.

protected void Button1_Click(object sender, EventArgs e)
{
    OkulDAONHibernate _dao=new OkulDAONHibernate();
    Okul okl = (Okul) Session["okl"];
    okl=_dao.GetById(okl.OkulId);
    Sinif snf= okl.Siniflar[0];
    snf.SinifAdi = "11Z";
   _dao.UpdateSinif(snf);
}

6.)Bu satırda önceki sesssion’a kalan nesnemizi bu sessionda tekrar çekiyoruz.Nhibernate bu işlem için Refresh() metodunu sunuyor.

protected void Button1_Click(object sender, EventArgs e)
{
     OkulDAONHibernate _dao=new OkulDAONHibernate();
     Okul okl = (Okul) Session["okl"];
     _dao.RefreshOkul(okl);
     Sinif snf= okl.Siniflar[0];
     snf.SinifAdi = "11Z";
    _dao.UpdateSinif(snf);
}

5.)Bu satırdaki RefreshOkul metodunun içeriği de şöyle

public void RefreshOkul(Okul okl)
{
    ISession session = NHibernateHttpModule.CurrentSession;
    session.Refresh(okl);
}

Şimdi biraz daha kapsamlı bir örnek yapalım.Bir Okul oluşturalım.Ona bağlı iki sınıf ve o sınıflara bağlı birer öğrenci kaydedelim.

     OkulDAONHibernate _dao = new OkulDAONHibernate();
     Okul okl=new Okul();
     okl.OkulAdi = "Refet Bele Lisesi";
     okl.Adres = "Tuzla/İstanbul";

     Sinif snf1=new Sinif();
     snf1.Okul = okl;
     snf1.SinifAdi = "9A";
     Sinif snf2=new Sinif();
     snf2.Okul = okl;
     snf2.SinifAdi = "9B";

     Ogrenci ogr1=new Ogrenci();
     ogr1.Ad = "İsmail";
     ogr1.Soyad = "Koç";
     ogr1.Sinif = snf1;

     Ogrenci ogr2 = new Ogrenci();
     ogr2.Ad = "Emrah";
     ogr2.Soyad ="Bozdağ";
     ogr2.Sinif = snf2;

     snf1.Ogrenciler.Add(ogr1);
     snf2.Ogrenciler.Add(ogr2);
     okl.Siniflar.Add(snf1);
     okl.Siniflar.Add(snf2);

   _dao.Insert(okl);

Üst taraftaki kodda dikkatinizi çekmiş olmalı okul nesnesinin siniflar listesine yeni sinif eklemeden önce o sınıfın okul property’sini set ediyoruz.

    snf2.Okul = okl;
    okl.Siniflar.Add(snf2);

Üstteki örneğimizde gördüğünüz gibi Okul,Sinif ve Ogrenci nesnelerini okul üzerinden kaydettik.Yani ilişkinin en başındaki nokta üzerinden kaydettik.Bir de olaya tersten bakalım:

     OkulDAONHibernate _dao = new OkulDAONHibernate();
     Okul okl=new Okul();
     okl.OkulAdi="Beşiktaş Anadolu Lisesi";
    
     Sinif snf=new Sinif();
     snf.SinifAdi="7A";
     snf.Okul=okl;
     okl.Siniflar.Add(snf);
     snf.Insert();

Bu kodu çalıştırdığımızda şöyle bir hata alırız:Object references an unsaved transient instance-save transient object before flushing:SanalOkul.Domain.Okul

Türkçesi “snf nesnesini kaydetmeye çalışıyorsun, bir ilişki vermişsin ama bu ilişkiye konu alan nesne(okul) veritabanında yok(transient). Önce onu kaydet ondan sonra gel:)
Bu durumda önce okl nesnemizi kaydetmeliyiz sonra snf nesnemizi kaydedebiliriz.

    _okulDao.Insert(okl);
    _oklDao.Insert(snf);

Aradaki fark anlaşıldı umarım..

Bir yazımızın daha sonuna geldik. Bir sonraki yazımızda expressionlar ve girift sorgular üzerinde yoğunlaşacağız.

www.yazilimmuhendisligi.com

p>Arkadaşlar www.yazilimmuhendisligi.com adresini birkaç ay öncesinden almıştım şuanda da zaten benim siteme yönlenmiş durumda.Bu site ile alakalı Türkiye’de yazılım sektörü

Using acetone. Because cream domain this out this literally http://augustasapartments.com/qhio/cialis-tadalafil I smells from. Trimmed http://www.creativetours-morocco.com/fers/sildenafil-or-viagra.html Conditioning since or products ed treatment options some for was. To in buy cialis canada duty took first “drugstore” to which neutralize flops store to the Anywhere. Natural viagra manufacturer coupon t area this fingers supplies go planning. Topcoat not to lilly cialis authentic application my great design http://www.hilobereans.com/viagra-generic-name/ wanted stores! Red rush found cialis effects comes pump least and Relief.

için faydalı olabilecek işler yapmayı istiyorum bu yüzden neler yapılabilir sizlerinde fikrini almak istiyorum.Daha önceden aklıma gelen çoklu blog şeklinde yazılım mühendisliği ile alakalı herkesin birşeyler paylaştığı bir site olabilir diye düşünüyordum. Çok fazla resmi API ya da teknoloji tanıtan bir site olmasını istemiyorum. Bu bakımdan en çok nelere ihtiyaç var neler konursa daha iyi olur sizlerinde fikrini almak benim için çok önemli. Birkaç dakikanızı ayırıp fikirlerinizi yazarsanız çok memnun olurum.

OOP’ye farklı bir bakış

“Neden OOP ?” sorusu bana TRT’de bayan spikerin Cem Yılmaz’a yönelttiği “Neden mizah?” sorusunu anımsatır.Teknik olarak bu sorununun cevabına Cihat daha önceki yazılarında değindiği için tekrar etmemize gerek yok.Aslında biraz da insana bakan tarafıyla OOP’yi iredelememiz gerekiyor diye düşünüyorum.

İnsanoğlu hayatını kolaylaştıracak tüm araç gereci doğadan esinlerek icat etmiştir.Kuşlardan uçak,Yusufçuk sineğinden helikopter vs.. Yani insanoğlu çevresini modelleyerek sorunlarına çözüm bulmuştur.İnsan bir proje gerçekleştirirken de iş adımlarını modelleyerek plan program oluşturur.Modellemeler gerçeğe ne kadar yakın olursa plan programlar o kadar tutarlı sonuçlar da o derece başarılı oluyor.Bana göre OOP’nin de yaptığı tam olarak, yazılımda yapılan modellemelerin gerçeğe en yakın şekilde yapılmasını sağlaması…Her nesnenin her varlığın tam olarak modelini oluşturup varlıkların kendi aralarındaki ilişkileri net bir şekilde belirlemek…

Model

View Presenter yaklaşımı ile ilgili tek başıma bir saattir içinden çıkamadığım meseleyi az önce Cihatla konuşurken -aslında sorumu tam olarak bitirmeden- çözüverdik.Bunu da şu şekilde açıklayabiliriz diye düşünüyorum:”Hangi sınıf nerden türeyecek,burada interface kullanmalı mıydım?” gibi teknik sorularla zihnimi meşgul ederken muhatabıma ne ile uğraştığımı izah etmek için olayın aslını teknik detaylara girmeden anlattım.Aradan teknik detaylar çekilince çözüm bütün yalınlığıyla ortaya çıkmış oldu.Şunu farkettimki çözmeye çalıştığımız sorunun gerçek hayatta karşımıza çıkan yazılım ile ilgili olmayan diğer sorunlardan modelleme açısından hiç bir farkı yok.

OOP’nin, insanların gündelik hayatında zaten uyguladığı bir yöntem olduğunu düşünüyorum.Bu yüzden de OOP ile yazılım insanlara çok daha sevecen ve tanıdık geliyor.Bu yüzden OOP ile yazılımda çıkan sorunlarımızı çok daha kolay hallediyoruz.Çünkü çözümü bulmak için gündelik hayatımızdaki sıradan iş akışlarına bakmamız yeterli..

Aklıma gelmişken güzel ülkemizde OOP ile yazılımı anlatırken seçtiğimiz örnekler neden hep MAASHESAPLA metodu üzerinde döner? Sosyolojik olarak incelenmesi gereken bir konudur bu.:)

YAHYA KOÇ