Makale Özeti

NHibernate uygulama geliştiricinin sql sorguları yazmasına, tekrar eden ADO.NET kodları ile uğraşmasına gerek bırakmaz. Bu yönüyle uygulama geliştiricinin iş yükünü hafiflettiği ve tabiki üretkenliğini artırdığını söyleyebiliriz.

Makale

New Page 1

NHibernate - Şapkanın altı

NHibernate uygulama geliştiricinin sql sorguları yazmasına, tekrar eden ADO.NET kodları ile uğraşmasına gerek bırakmaz. Bu yönüyle uygulama geliştiricinin iş yükünü hafiflettiği ve tabiki üretkenliğini artırdığını söyleyebiliriz.

Ancak NHibernate bu işleri yaparken arka planda neler gerçekleştiriyor?

NHibernate kullanıcın tanımladığı mapping dosyasını kullanarak çalışma anında dinamik sql sorguları oluşturur. Örneğin bir veriye erişmek için SELECT sorgusunu oluştururken hbm.xml içindeki <class> elementide belirlenmiş özellikleri ve bu özelliklerin karşılık geldiği veritabanı sütunlarını bulur ve bu doğrultuda SELECT sorgusunu oluşturup veritabanı yönetim sistemi üzerinde sorguyu işletir. Sorgudan dönen sonucu ise .NET Framework yetenekleri arasında olan reflection yöntemi ile nesnelerin propertylerine atar. Zaten NHibernate ve benzeri araçlar reflection'ın yavaş çalışması göstergesine bağlı olarak bazı olumsuz eleştirilere maruz kalmaktadır.

NHibernate'in veritabanı üzeriden işlevleri gerçekleştirmek için oluşturduğu SQL sorgularını hata ayıklama (debug) yada herhangi bir amaçla izlemek istediğiniz ilk akla gelen çözüm SQL Server veritabanı yönetim içinde gelen araçlardan birisi olan SQL Profiler aracını kullanabilirsiniz. Ayrıca NHibernate'in loglama özelliklerini kullanarakta debug ve trace işlemlerini gerçekleştirebilirsiniz.

SQL Profiler ile sorguları izlemek

SQL Server Profiler aracını Start>All Programs>Microsoft SQL Server>Profiler kısayolunda açtıktan sonra profilerda yeni bir trace başlatabilirsiniz.

Burada kişisel olarak bir tavsiyeyi ve kullandığım bir yöntemi eklemek istiyorum. Sadece NHibernate ile değil herhangi bir uygulamanızın çalıştırdığı sorguları izlemek istiyorsanız filtreleme seçenekleri istediğiniz bilgiye daha kolay ulaşmanızı sağlayacaktır. Sadece bir veritabanını izleyecekseniz Filters sekmesinden DatabaseID özelliğine izlemek istediğiniz veritabanının id sini yazın. DatabaseName filtresi sanırım bir bugdan dolayı çalışmıyor. Veritabanınız id sinin ne olduğunu ise select db_id('northwind') şeklinde öğrenebilirsiniz. Northwind yerine ID'sini öğrenmek istediğiniz veritabanı ismini yazmanız ve sorguyu query analyzer gibi bir arabirim ile çalıştırmanız yeterlidir.

Eğer sadece veritabanın ne olduğu farketmeksizin kendi uygulamanızdan gelen sorguları görmek için bir filtre oluşturmak istiyorsanız. Uygulamanızda bağlantı için kullandığınız ConnectionString değerine Application Name değerini eklemeniz gerekmektedir. Örneğin server=.;database=pubs;user id=sa;password=;application name=BenimUygulamam1; gibi bir connectionstring ifadesinde application name olarak BenimUygulamam1 verildi ise Profiler dan Application Name filtresi BenimUygulamam1 olarak belirlendiğinde sadece o uygulamanın gönderdiği sorguları izlersiniz.

 

Kendi uygulamalarımda Profiler üzerinde izleme yapmak istediğimde Application Name filtresini kullanmayı tercih ediyorum. Aksi halde başka uygulamaların (örneğin sql agent service) çalıştırdığı sql sorguları gereksiz yere trace logları arasına ekleniyor ve istediğiniz veriye ulaşmanızı yavaşlatıyor.

NHibernate MusteriID değeri 1 olan Musteri nesnesine ait verileri SQL Server üzerinden almak için nasıl bir sorgu oluşturmuş?

Daha önceki makalede örnek olarak kullandığımız NHibernate kod parçasının oluşturduğu sorguyu Profiler ile izleyelim. NHibernate tarafında çalışan C# kodu aşağıda gözükmektedir.

      NHibernate.Cfg.Configuration cf=new NHibernate.Cfg.Configuration();

      cf.AddAssembly(this.GetType().Assembly);

      NHibernate.ISessionFactory f=cf.BuildSessionFactory();

      NHibernate.ISession s=f.OpenSession();

      Musteri m;

      m=s.Get(typeof(Musteri),1) as Musteri;

      s.Close();

      if (m==null)

      {

        MessageBox.Show("Müşteri bulunamadı.");

      }

      else

      {

        MessageBox.Show(m.ToString());

      } 

Profiler'dan trace başlatılıp sorgular izlendiğinde aşağıdaki sonuç gözlemlenmektedir.

exec sp_executesql N'SELECT musteri0_.MusteriID as MusteriID0_, musteri0_.Ad as Ad0_, musteri0_.KayitTarihi as KayitTar4_0_, musteri0_.Aktif as Aktif0_, musteri0_.Soyad as Soyad0_ FROM Musteri musteri0_ WHERE musteri0_.MusteriID=@p0', N'@p0 int', @p0 = 1

NHibernate'in oluşturup çalıştırdığı sorgu yukarıda gözükmektedir.

Bu noktada tekrar vurgulamak gerekir ise sorgular NHibernate tarafında oluşturuldu ve veritabanı üzerinde çalıştırıldı. Dinamik oluşturulan sorgular "execution plan" belleklemesi gibi özelliklerden faydalanamaz. Bu durum NHibernate'in  kullanımı konusunda görüş ayrılıklarına sebep olduğu ve bazı görüşlere göre olumsuz eleştiriler aldığı bir noktadır. Ancak sonraki makalede bahsediyor olacağım "dynamic update" gibi özellikleri ise bu noktadaki eksi notunu telafi eder niteliktedir.

ISession.Update Metodu - NHibernate ile veri güncellemesi

      NHibernate.Cfg.Configuration cf=new NHibernate.Cfg.Configuration();

      cf.AddAssembly(this.GetType().Assembly);

      NHibernate.ISessionFactory f=cf.BuildSessionFactory();

      NHibernate.ISession s=f.OpenSession();

      Musteri m;

      m=s.Get(typeof(Musteri),1) as Musteri;

      if (m!=null)

      {

        m.Ad="Ali Kemal";

        s.Update(m);

        s.Flush();

      }

      s.Close();

Yukarıdaki kod bloğunda MusteriID değeri 1 olan musteri nesnesi Get metodu ile alınıyor ve nesnenin adresi m değişkenine atanıyor. Ardından bir if kontrolü ile veritabanından MusteriID'si 1 olan bir nesne olduğuna ve Get metodu ile alınabildiğine emin olunuyor, yani null kontrolü yapılıyor. Ardından nesnenin Ad özelliği Cengiz iken Ali Kemal olarak değiştiriliyor. Ardından veritabanından alınmış mevcut bir nesnenin son halini veritabanına yansıtmak için yani güncellemek için kullanılan Update metodu çağrılıyor. ISession arayüzünde yer alan Flush metodu yapılan değişiklerin veritabanına yansıtılması yani sorguların çalıştırılmasını sağlar. Ve sonuç olarak veritabanındaki musteri bilgilerinden Ad bölümünd artık Ali Kemal yazıyor.

Bu işlem gerçekleşirken Profiler aracılığı ile çalıştırılan sorguları izlediğimiz aşağıdaki birinci sorgunun Get metodu sonucu çalıştıralan SELECT sorgusu, ikinci sorgunun ise Update metodu sonucu çalıştırılan UPDATE sorgusu olduğunu görüyoruz.

exec sp_executesql N'SELECT musteri0_.MusteriID as MusteriID0_, musteri0_.Ad as Ad0_, musteri0_.KayitTarihi as KayitTar4_0_, musteri0_.Aktif as Aktif0_, musteri0_.Soyad as Soyad0_ FROM Musteri musteri0_ WHERE musteri0_.MusteriID=@p0', N'@p0 int', @p0 = 1

exec sp_executesql N'UPDATE Musteri SET Ad = @p0, KayitTarihi = @p1, Aktif = @p2, Soyad = @p3 WHERE MusteriID = @p4', N'@p0 nvarchar(4000),@p1 datetime,@p2 bit,@p3 nvarchar(4000),@p4 int', @p0 = N'Ali Kemal', @p1 = 'Mar 3 2005 12:00:00:000AM', @p2 = 1, @p3 = N'HAN', @p4 = 1

Profiler'ı kullanarak NHibernate'in kapalı kutu altında neler yaptığını ve nasıl veriye eriştiğini görmüş olduk. Sonraki makalemizde ise NHibernate'in bu sorguları oluşturması aşaması ufak düzenlemeler ile müdahale edip, dinamik güncelleme gibi özelliklerini inceliyor olacağız.

Cengiz HAN
Microsoft ASP.NET MVP
cengiz@cengizhan.com