15 Mayıs 2015 Cuma

Kalıtımsal Eşleme


Herkese merhabalar.

    Bugün sizlere kalıtımsal eşleme ve nasıl gerçekleştireceğimizden bahsedeceğim. Kalıtım denilince benim aklıma gelen ilk şey ata bir sınıf ve bu ata sınıftan türeyen bir alt sınıftır. Gelin kalıtım konusunu bir detaylandıralım. C# nesne tabanlı bir programlama dilidir, ve bu özellik C#'ın en önemli özelliklerinden biridir. C# yüzde yüz nesne tabanlı dil olması nedeniyle programcılara birçok yönden kolaylıklar sağlamaktadır. Peki bu kalıtım nedir ne işe yarar program geliştiricilere ne gibi kolaylıklar sağlar [1].

    Kalıtım, nesne yönelimli programlamanın en önemli özelliklerinden biridir. Miras alma yolu ile sınıflar birbirinden türetilebilir. Yani mevcut sınıflardan yeni bir sınıf üretme şekli olarak tanımlanabilmektedir. Bu işlemde, türeyen sınıflar türemiş sınıf, kendisinden yeni sınıfların oluşturulduğu sınıflara ise temel sınıf adı verilir [2].

    Türeyen sınıflar, türedikleri sınıfların özelliklerini devralırlar, bununla birlikte kendilerine de özel olarak özellikleri mevcuttur. .NET ortamında bir sınıf sadece bir sınıftan türeyebilir; fakat bir temel sınıf bir çok sınıf türetebilir. Miras almanın temel amacı sınıflar arasında ilişki kurmaktır [2]. Gelin hep birlikte kalıtımın Fluent NHibernate'deki kullanımına bir bakalım.

Kalıtımın Fluent NHibernate'deki kullanımı aşağıdaki üç şekilde gerçekleşmektedir.

  • Table Per Hierarchy (TPH);
  • Table Per Type (TPT);
  • Table Per Concrete Class (TPC).


Table Per Hierarchy (TPH):


    TPH kalıtım yönteminde kalıtım, veritabanının discriminator kısmı gibi herhangi bir koşul ile tanımlanan  koşullu eşleştirmeye bağımlıdır. Ayrıca, kalıtım ağacı sadece bir tablodan üretilmiştir [3].

Table Per Type (TPT):


    TPT, veritabanının ayrı tablolarında açıklanan kalıtımdır. Her tablo ilave olarak detay bulundurur. Bu detaylar, tablonun atasına bağlı olan yeni tipleri açıklamaktadır [3].

Table Per Concrete Class (TPC)


    Bu tip kalıtımda, her sınıf kendi tablosunu içerdiği bir kalıtım hiyerarşisi içerisindedir. Genel özellikler, ayrı bir tabloya konmaktansa her bir tablo içerisine tekrar tekrar yazılır [3].

Kalıtım tiplerini inceledikten sonra gelin hep birlikte bir örnek üzerinden kalıtımı daha iyi anlayalım.

 public class Iletisim  
 {  
   public virtual Guid Id { get; set; }  
   public virtual string Baslik{ get; set; }  
   public virtual string İcerik { get; set; }  
 }  
 public class SMS : Iletisim  
 {  
 }  
 public class Mail : Iletisim  
 {  
 }  


 public class IletisimMap : ClassMap<Iletisim>  
 {  
   public IletisimMap()  
   {  
     Table("Iletisim");  
     Id(x => x.Id).GeneratedBy.GuidComb();  
     DiscriminateSubClassesOnColumn("IletisimTip");  
     Map(x => x.Baslik);  
     Map(x => x.Icerik);  
   }  
 }  

 public class SMSMap : SubclassMap<SMS>  
 {  
   public SMSMap()  
   {  
     DiscriminatorValue(1);  
   }  
 }  
 public class MailMap : SubclassMap<Mail>  
 {  
   public MailMap()  
   {  
     DiscriminatorValue(2);  
   }  
 }  

Yukarıda oluşturulan yapıda Iletisim isimli bir ana sınıf ve bu sınıftan türeyen iki alt sınıf olan SMS ve Mail sınıfları bulunmaktadır. Kullanılan DescriminateSubClassesOnColumn metodu ile hangi alt sınıfın yaratılacağı belirlenir. Ayrıca belirlenmiş olan Discriminator değerleri ile iletişim tipi belirlenerek hangi alt sınıfın yaratılacağının Fluent NHibernate tarafından anlaşılması sağlanmış olur [4].

Yukarıda kurmuş olduğumuz yapı ile kalıtım sağlanmış olur ve discriminator kullanımının ne işe yaradığını da görmüş oluyoruz. Bu haftalık anlatacaklarım bu kadar, umarım faydalı bir yaz olmuştur hoşçakalın..

Kaynaklar 


[1]C# İle Kalıtım(inheritance)- Override ve Virtual Metodlar, http://www.ramazancelikkaya.com/makaleOku/CSharp/131/C, Mayıs 7, 2015.

[2]Inheritence – Miras Alma (Kalıtım), http://www.ismailgursoy.com.tr/inheritence-miras-alma-kalitim/, Mayıs 8, 2015.

[3]Inheritance mapping strategies in Fluent Nhibernate, http://www.codeproject.com/Articles/232034/Inheritance-mapping-strategies-in-Fluent-Nhibernat, Mayıs 8, 2015.

[4]Fluent NHibernate - Table Inheritance - Discriminators, http://www.philliphaydon.com/2011/08/fluent-nhibernate-table-inheritance-discriminators/, Mayıs 9, 2015.

1 Mayıs 2015 Cuma

Convention Sınıflarının Yeniden Yazılması


Herkese merhabalar.

 Bugün sizlere, önceki yazılarda bahsetmiş olduğum convention sınıflarını nasıl kendimize göre değiştirebileceğimizden bahsedeceğim. Öncelikle convention sınıflarının ne olduğunu bir hatırlayalım. Convention sınıfları, tablo ve kolon isimlendirmelerini yaparken bize yardımcı olan default sınıflardır. İsimlendirme sınıflarından bazılarını hatırlayalım. Önceki haftalarda detaylı bir şekilde anlattığım için sadece bazı isimlerini hatırlatacağım [1].

  • ColumnNullabilityConvention
  • PrimaryKeyNameConvention
  • StringColumnLengthConvention
  • IClassConvention
  • IIdConvention
  • IHasManyConvention
  • IReferenceConvention 

 
      İsimlendirme sınıflarını neden değiştirelim ki dediğinizi duyar gibiyim. Örneğin; StringColumnLengthConvention'ın default sınıfında, string tipindeki kolonun uzunluk sınırı belirtilmediyse bu sınıf sayesinde otomatik olarak uzunluk 100 olarak atanır [1]. Eğer bu uzunluğun 100 değil de 50 olmasını istiyorsanız, default olan isimlendirme sınıfını kendinize göre uyarlayıp bu yapıyı kullanabilmeniz gerekiyor.

    İsimlendirme sınıfları(conventions), birçok interface ve ana sınıflar kullanılarak oluşmuş olan sınıflardır [2]. Bu sınıfların her birinde Apply metodu tanımlanmıştır. Bu metot, isimlendirme sınıfının çeşidine göre parametreler almaktadır [3]. Bu metot, eşleştirmelerinize yapmış olduğunuz değişimin yapıldığı yerdir [2]. Eşleştirme sınıfınızın yapısını oluşturduktan sonra default olan isimlendirme sınıfları uygulanır. Aşağıdaki örnek ile isimlendirme sınıflarının mantığını daha iyi anlayacaksınız.

 public class KisiMap : ClassMap<Kisi>  
 {  
  public KisiMap()  
  {  
   Id(x => x.Id);  
   Map(x => x.Ad)  
    .Column("TumAd")  
    .Length(100);  
   Map(x => x.Yas);  
  }  
 }  

Yukarıda belirlemiş olduğumuz mapping sınıfımıza göre, isimlendirmemizin akış şeklini açıklayacağım; kullanmış olduğunuz high-level metodlara bakarak, convention sınıfı mapping sınıfınızın Kisi sınıfı olduğunu, Ad ve Yas olarak iki özelliğinizin olduğuna karar verir. Daha sonra, convention sınıfları, kolon isimleri, uzunluğu gibi değerlere uygulanır [2]. Convention(isimlendirme) sınıflarımızın çalışma yapısını anladıktan sonra, gelin kendi örneğimize bir bakalım.

 public class LowercaseTableNameConvention : IClassConvention  
 {  
  public void Apply(IClassInstance instance)  
  {  
   // değiştirme yapılacak yer..  
  }  
 }  

Yukarıdaki kod ile tablo ismimizi belirleyebilmemiz mümkün; ancak Apply metodunun içerisine tablo isimlerimizin ne yapıda olacağını yazmalıyız.

 public void Apply(IClassInstance instance)  
 {  
  instance.Table("tbl_" + instance.EntityType.Ad);  
 }  

Yukarıda gördüğünüz üzere, IClassInstance interface'i sayesinde Table metodunu kullanarak convention sınıfımızın tablo ismini kendimize göre yazmak bu kadar kolay [2]. Dilediğiniz convention sınıfını Apply metodu sayesinde yukarıdaki şekilde kendinize göre uyarlayabilirsiniz.

Bu haftalık anlatacaklarım bu kadar. Bir sonraki yazıda buluşmak üzere, hoşçakalın..


Kaynaklar


[1] Fluent NHibernate conventions-examples, http://marcinobel.com/index.php/fluent-nhibernate-conventions-examples/, Nisan 27, 2015.

[2] Conventions, https://github.com/jagregory/fluent-nhibernate/wiki/Conventions, Nisan 27, 2015.

[3] Changing The FluentNHibernate Id Conventions, http://candland.net/2009/09/14/changing-the-fluentnhibernate-id-conventions/, Nisan 27, 2015.




26 Nisan 2015 Pazar

Fluent NHibernate Automapping(Otomatik Eşleme)


    Herkese merhabalar.

   Bugün sizlere Fluent NHibernate'in sağlamış olduğu kolaylıklardan bir tanesi olan otomatik eşlemeden bahsedeceğim.  Büyük uygulamalarda modellerinizin eşleştirmelerini yapmak size oldukça sıkıcı gelebilir. Bu durumdan sizi kurtarmak üzere otomatik eşleştirme yardımınıza koşacak. Automapping kavramı; isimlendirme grupları kullanılarak gerçekleştirilen ve objelerinizi otomatik bir şekilde sınıflandıran mekanizmadır [1]. Otomatik eşleştirmede isimlendirme gruplarına(conventions) neden ihtiyaç duyuyoruz dediğinizi duyar gibiyim. Otomatik eşleştirme yaparken eğer convention sınıflarınızı default olarak kullanıyorsanız, otomatik eşleştirici eşleştirme yaparken örneğin; Id isimli integer tipindeki değişkeninizin otomatik olarak artış gösteren bir öncül anahtar(primary key) olduğunu anlaması gerekmektedir [2]. Aşağıdaki örnek ile otomatik eşleştirmenin yapılmasını sağlayan bazı kavramları öğreneceğiz.

 public class Yiyecek  
 {  
  public int Id { get; set; }  
  public virtual string Ad { get; set; }  
  public virtual decimal Fiyat { get; set; }  
 }  
 public class Buzdolabı  
 {  
  public virtual int Id { get; set; }  
  public virtual IList<Yiyecek> Yiyecekler { get; set; }  
 }  

Yukarıdaki kod ile one-to-many ilişkisi kurulmuştur. Bir buzdolabında birden fazla yiyecek bulunabilir. Otomatik eşleştirmemizi yapabilmemiz için Automap sınıfını, fluent konfigürasyon API kombinasyonu ile kullanmalıyız.

 AutoMap.AssemblyOf<T>  

Yukarıdaki kod parçası generic bir tip alan statik bir metottur. Otomatik eşleştirmenizi yapmak istediğiniz sınıfınızı T değişkeninin yerine yazmalısınız. İşte otomatik eşleştirme yapmak bu kadar kolay.  AutoMap.AssemblyOf<Yiyecek>  kodunu çağırdığınız zaman;  Yiyecek sınıfının tanımlandığı assembly'ye bağlanan AutoPersisteneceModel objesi üretilir [3]. Kullanacağımız SessionFactory'i yaratmak için aşağıdaki kod parçasını kullanmalıyız.

 var sessionFactory = Fluently.Configure()  
  .Database(/* database config */)  
  .Mappings(m =>  
   m.AutoMappings  
    .Add(AutoMap.AssemblyOf<Yiyecek>()))  
  .BuildSessionFactory();  

    Automapper, hangi sınıfın objeniz veya servisiniz olduğunu ayırt edemez. Bu yüzden ihtiyacımız olan final bir metot olan Where(Func)'i kullanmalıyız. Bu metot ile genellikle namespace sınırlaması konulur; ancak siz Type objesi ile istediğiniz sınırlamayı koyabilirsiniz [1]. Bu örnekte ben de namespace sınırlamasına ihtiyaç duyuyorum.


 var autoMappings = AutoPersistenceModel  
  .MapEntitiesFromAssemblyOf<Yiyecek>()  
  .Where(t => t.Namespace == "Mutfak.Entities");  
 var sessionFactory = new Configuration()  
  .AddProperty(ConnectionString, ApplicationConnectionString)  
  .AddAutoMappings(autoMappings)  
  .BuildSessionFactory();  

Yukarıdaki şekilde namespace sınırlamamızı koyduktan sonra otomatik eşleştirmemizi tamamlamış olduk. Gördüğünüz gibi yukarıdaki yapıyı kullanarak otomatik eşleştirme yapmak bu kadar basit.  Bu haftalık anlatacaklarım bu kadar. Bir sonraki hafta; isimlendirme sınıflarımızı kendimize göre nasıl uyarlayabileceğimizden bahseceğiz, hoşçakalın..

Kaynaklar


[1] Fluent NHibernate: Auto Mapping Introduction, http://www.jagregory.com/writings/fluent-nhibernate-auto-mapping-introduction/, Nisan 22, 2015.

[2]GETTING STARTED WITH FLUENT NHIBERNATE AND AUTO MAPPING IN C#, http://blog.json.codes/web-development/getting-started-with-fluent-nhibernate-and-auto-mapping-in-c/, Nisan 22, 2015.

[3] Auto mapping, https://github.com/jagregory/fluent-nhibernate/wiki/Auto-mapping, Nisan 23, 2015.

19 Nisan 2015 Pazar

Fluent NHibernate ile Kullanıcı Tanımlı Tipler Kullanmak



    Herkese merhabalar.


    Bugün sizlere, Fluent NHibernate kullanırken kullanıcı tanımlı tiplerin nasıl kullanıldığından bahsedeceğim. Kullanıcı tanımlı tip derken ne demek istediğimi enum(enumeration) kavramını açıklayarak ifade etmek istiyorum. Program içerisinde kullanılan sabitlerin anlamlandırılması ile sabitlere isim vererek bir grup altında toplayabiliriz. İşte bu gruplara enum(enumaretion) denmektedir. Enum içerisindeki elemanlar, dizilerdeki gibi 0 sıra numarasından başlamak üzere sıralanır [1]. Enum kullanımını daha iyi anlamamız açısından, enum denilince akla gelen klasik örneği sizlerle paylaşmak istiyorum.

   Örneğin; programımızda haftanın günlerini kullanmak isteyelim. Bu günler ile karmaşık işlemler yapmak isteyelim. Bunun için  her güne sayısal değer vermemiz bizim işimizi görecektir. Pazartesi, Salı, Çarşamba, Perşembe, Cuma, Cumartesi, ve Pazar’a 0,1,2,3,4,5 ve 6 tam sayı değerlerini tanımlamamız yeterli olacak ve bu tam sayılar üzerinden işlemlerimizi gerçekleştireceğiz. Öte yandan, sıfırı (0) kullandıktan ve bir süre sonra koda baktığımızda sıfırın Pazartesi gününü ifade ettiğini hatırlayamayabiliriz. Bu durumda, C# bizlere güzel bir çözüm sunar. Bu çözümde; değerlerin grup sembolik bir ad ile bildirilebileceği "enum" anahtar sözcüğü kullanılır [2]. Enumeration türünü aşağıdaki şekilde tanımlayabiliriz.

 Enum HaftaGunler  
 {  
 Pazartesi,  
 Sali,  
 Carsamba,  
 Persembe,  
 Cuma,  
 Cumartesi,  
 Pazar  
  }  

Enumeration türünü yukarıdaki şekilde tanımladıktan sonra aşağıdaki şekilde erişebiliriz.


 HaftaGunler gun = HaftaGunler.Pazar;  
 MessageBox.Show(gun.ToString());  

Böylelikle, mesaj kutumuzda "6" yazacaktır. Haftanın günlerinin hepsini birden almak istersek .GetNames() metodunu kullanırız. Bu metot yardımıyla enum içerisinde kullandığımız değerleri  string formatında bir dizide aşağıdaki şekilde kullanabiliriz [2].

  string[] gunler = Enum.GetNames(typeof(HaftaGunler));  

    Şimdi de enumların Fluent NHibernate'teki kullanımına bakalım. Fluent NHibernate ile özel bir kullanıcı tipi tanımlanmak istendiğinde, IUserType arayüzünden kalıtılmış bir sınıf ile ilgili tipi tanımlayabiliriz [3]. Aşağıdaki kod örneğinde, lisans ve yüksek lisans öğrenci tipini içeren enum kullanılmıştır [4].

 public enum Ogrencitipi  
 {  
   Lisans,  
   Yukseklisans  
 }  

 using System;  
 using System.Data;  
 using NHibernate.SqlTypes;  
 using NHibernate.UserTypes;  
 namespace YourNamespace.Persistence.Mappings.CustomTypes  
 {  
   public class OgrencitipiMap : IUserType  
   {  
     new public bool Equals(object x, object y)  
     {  
       return object.Equals(x, y);  
     }  
     public int GetHashCode(object x)  
     {  
       return x.GetHashCode();  
     }  
     public object NullSafeGet(IDataReader rs, string[] names, object owner)  
     {  
       object r = rs[names[0]];  
       var value = (string)r;  
       if (string.IsNullOrEmpty(value))  
         throw new Exception("Geçersiz!");  
       switch (value)  
       {  
         case "L":  
           return Ogrencitipi.Lisans;  
         case "Y":  
           return Ogrencitipi.Yukseklisans;  
         default:  
          throw new Exception("Geçersiz öğrenci tipi!");  
       }  
     }  
     public void NullSafeSet(IDbCommand cmd, object value, int index)  
     {  
       object paramVal = 0;  
       switch ((Ogrencitipi)value)  
       {  
         case Ogrencitipi.Lisans: paramVal =  
          "L"; break;  
       case Ogrencitipi.Yukseklisans: paramVal =  
          "Y"; break;  
         default:  
           throw new Exception("Geçersiz öğrenci tipi!");  
       }  
       var parameter = (IDataParameter)cmd.Parameters[index];  
       parameter.Value = paramVal;  
     }  
     public object DeepCopy(object value)  
     {  
       return value;  
     }  
     public object Replace(object original, object target, object owner)  
     {  
       return original;  
     }  
     public object Assemble(object cached, object owner)  
     {  
       return cached;  
     }  
     public object Disassemble(object value)  
     {  
       return value;  
     }  
     public SqlType[] SqlTypes  
     {  
       get { return new SqlType[] { new StringSqlType() }; }  
     }  
     public Type ReturnedType  
     {  
       get { return typeof(Ogrencitipi); }  
     }  
     public bool IsMutable  
     {  
       get { return false; }  
     }  
   }  
 }  

Mapping sınıfınızda aşağıdaki şekilde eşleştirmenizi yapabilirsiniz.

  //NHibernate 2.X  
   Map(x=>x.Ogrencitipi).CustomType<OgrencitipiMap>();  
   //NHibernate 3.X  
   Map(x=>x.Ogrencitipi).CustomTypeIs<OgrencitipiMap>();  

Yukarıdaki örnekte gördüğünüz gibi enum yapısını kullanarak istediğiniz verileri Fluent NHibernate projenizde kullanabilirsiniz. Enum kullanımının faydaları; kod okunabilirliğini arttırması, muhtemel değer kümesinin daraltılması ve tip güvenliğini sağlaması dolayısıyla hata payını en aza indirmesidir [5]. Böylelikle yeri geldiğinde projemizde enum kullanımının nasıl gerçekleşeceğini görmüş olduk.

    Umarım faydalı bir yazı olmuştur, hoşçakalın..

Kaynaklar


[1]C# ile Enum Kullanımı, http://sanalkurs.net/c-ile-enum-kullanimi-8423.html, Nisan 15, 2015.

[2]C# ve Enumeration (Enum) Kullanımı, http://emraheroglu.blogspot.com.tr/2010/01/c-ve-enumeration-enum-kullanm.html, Nisan 16, 2015.

[3]Fluent NHibernate ile kullanıcı tanımlı tipler kullanmak, http://b.zor.lu/fluent-nhibernate-ile-kullanici-tanimli-tipler-kullanmak/, Nisan 16, 2015.

[4]USING AN ENUM ON A FLUENTNHIBERNATE MAPPING [C#], http://crodrigues.com/using-a-enum-on-a-fluentnhibernate-mapping-c/, Nisan 17, 2015.

[5]Daha Okunabilir Kod ve Yaşanabilir Dünya İçin Enum’lar, http://kodcu.com/2014/08/okunabilir-kod-ve-enum/, Nisan 17, 2015.

11 Nisan 2015 Cumartesi

HQL (Hibernate Query Language)

Herkese merhabalar.

   Doğrudan SQL sorgularını kullanarak veritabanı üzerinde işlemler gerçekleştirmek istemiyorsanız; nesneler üzerinde işlem yaparak da veritabanı işlemlerinizi gerçekleştirebileceğiniz bir sorgu dili mevcut. Bugün sizlere Hibernate'in sorgu dilinden bahsetmek istiyorum. Hibernate sorgu dili, SQL'e benzer özellikleri olan nesne tabanlı bir sorgu dilidir. HQL'in SQL'den en önemli bilinmesi gereken farkı; SQL kolonlar ve tablolar üzerinde işlem yaparken, HQL objeler ve diğer özellikler üzerinde işlemlerini gerçekleştirir. HQL, Hibernate tarafından, veritabanı üzerinde doğrudan işlem gerçekleştirebilen SQL'e dönüştürülür. Şu unutulmamalıdır ki veritabanı ile en yakın olan katman her zaman SQL'dir [1]. 

   HQL yazarken büyük-küçük harf duyarlılığına dikkat edilmelidir. WHERE, SELECT, FROM gibi kelimeler de  büyük-küçük harf duyarlılığı aranmazken; tablo ve kolon isimleri gibi özellikler yazılırken büyük-küçük harf duyarlılığı mevcuttur. Şunu da eklemek istiyorum; HQL'in güzel özelliklerinden birisi de  veritabanından bağımsız yazılan bir sorgu dili olmasıdır [1].  Gelin hep birlikte HQL'de en çok kullanılan kalıplara bakalım.

from ve as 

 from obje [as nil_obje]*   
 obje_adi  
  
   Genellikle select ile kullanılır. Sorguda istenilen cevabın hangi tablodan çekileceğini belirtir. "as" ifadesi ile uzun ve kullanımı zor olan tablo veya alan adlarına geçici olarak kısa isimler vererek bunları kodlamamızda kullanabiliriz [2]. Böylece mevcut tablo yapımız bozulmadan dinamik olarak belirlediğimiz isimleri kullanabilmekteyiz.

select


Sorgunun sonuç kümesinde ne olacağını belirten sözcüktür [2].

 select ogrenciisim from bilgisayarMuhendisligi as bilgisayarogrencisi  


where


   Sorgu kümesinde dönmesi istenen durumların istenen koşullar doğrultusunda dönmesini sağlayan sözcüktür. =, >, AND, NOT  gibi operatörler kullanılır [2].

  select ogrenciisim from bilgisayarMuhendisligi as bilgisayarogrencisi where ogrenci_no > 10   

Birleşik Değerli Fonksiyonlar


   Birleşik değerli fonskiyonlar kullanılarak, yapılan sorgulama alanı daraltılarak çalışma süresi optimize edilebilir [2,3].

  • avg(): Ortalama değeri döndürür.
  • count(): İstenilen değere bağlı kayıt sayısını döndürür. Boş değer içeren kaydı saymaz.
  • count(*): İstenilen değere bağlı kayıt sayısını döndürür. Boş değer içeren kaydı sayar.
  • first(): İlk değeri döndürür.
  • last(): Son değeri döndürür.
  • max(): En büyük değeri döndürür.
  • min(): En küçük değeri döndürür.
  • sum(): Toplam değeri döndürür.


 select count(Meslek) from tblKomsular  


Insert Kullanımının SQL'den Farkı



   Bilinmesi gereken önemli noktalardan birisi; HQL'de doğrudan tabloya ekleme yapamazsınız; ancak bir tablodan diğer tabloya ekleme yapabilirsiniz [1].

Alt Sorguların Kullanımı


   Alt sorgular, sorgusu oldukları ana sorgudan önce çalıştırılırlar. Parantez içine yazılılırlar ve "where" sözcüğüyle birlikte kullanılarak istenilen sorgu yanıtının aralığını daraltmaya yardımcı olurlar [1,4].

 select bolumad from bolumler as bolum where bolumgelir> (bolumgelir avg() from bolum)  

Örnek HQL Sorgusu

 var bloglar = s.CreateQuery("from Blog b where b.Baslik = :baslik and b.Altbaslik = :altbaslik")  
   .SetParameter("baslik","Nil Busra Ozer Kisisel Blog")  
   .SetParameter("altbaslik", "Hibernate Query Language")  
   .List<Blog>();  

 
   Bugünlük anlatacaklarım bu kadar. HQL çok derin bir konu olduğu için özellikle temel kullanımlarına değinmek istedim. Bir sonraki yazımda görüşmek üzere, hoşçakalın..

Kaynaklar


[1]HibernateQueryLanguage,http://www.tutorialspoint.com/hibernate/hibernate_query_language.htm, Nisan 8, 2015.

[2]Introducing HQL: The Object-Oriented Query Language from Hibernate, http://www.developer.com/open/article.php/3322131/Introducing-HQL-The-Object-Oriented-Query-Language-from-Hibernate.htm, Nisan 8, 2015.

[3]Using HQL (Hibernate Query Langıage), http://docs.castleproject.org/Active%20Record.Using%20HQL%20(Hibernate%20Query%20language).ashx, Nisan 9, 2015.

[4]NHibernate Queries-Examples, http://ayende.com/blog/4023/nhibernate-queries-examples, Nisan 9, 2015.



5 Nisan 2015 Pazar

Fluent NHibernate CRUD İşlemleri


Herkese merhabalar.

   Bugün sizlere Fluent NHibernate'in temel konusu olan CRUD işlemlerinden bahsedeceğim. Bu işlemleri gerçekleştirmeyi öğrendiğinizde Fluent NHibernate'i daha iyi kavramaya başlayacağınızı fark edeceksiniz. Gelin hep birlikte aşağıdaki örneğimiz ile bu işlemleri anlayalım.

   Örneğimizde teknoloji isimli bir veritabanımız olacak. Bu veritabanımızda, Marka, Telefon ve Televizyon tablolarını oluşturup bunlar üzerinde okuma, kayıt ekleme, kayıt silme ve kayıt güncelleme işlemlerini gerçekleştireceğiz.

   Önceki yazımda bahsettiğim şekilde gerekli dll dosyalarımızı projemize ekleyelim.



   Solution explorer'ımıza aşağıdaki şekilde uygun klasörlerin altında sınıflarımızı  oluşturalım.

   Örneğimizde; iki teknolojik cihaz ve bunların markaları üzerinden gideceğiz. Telefonun marka ile ve Televizyonun marka ile many-to-one ilişkisi vardır. Şöyle ki; bir telefonun bir markası var iken bir marka birden fazla telefona hatta farklı televizyon gibi telefondan farklı cihazların markası olabilmektedir.


Marka.cs


 using System;  
 using System.Collections.Generic;  
 using System.Linq;  
 using System.Text;  
 using System.Threading.Tasks;  
 namespace TelefonFluentHibernate.Entites  
 {  
   class Marka  
   {  
     public virtual int MarkaId { get; set; }  
     public virtual string MarkaAd { get; set; }  
   }  
 }  

Telefon.cs


 using System;  
 using System.Collections.Generic;  
 using System.Linq;  
 using System.Text;  
 using System.Threading.Tasks;  
 namespace TelefonFluentHibernate.Entites  
 {  
   class Telefon  
   {  
     public virtual int telefonId{get; set;}  
     public virtual string telefonAd { get; set;}  
     public virtual string telefonRenk { get; set; }  
     public virtual int telefonFiyat { get; set; }  
     public virtual Marka telefonMarka { get; set; }  
   }  
 }  

Televizyon.cs


 using System;  
 using System.Collections.Generic;  
 using System.Linq;  
 using System.Text;  
 using System.Threading.Tasks;  
 namespace TelefonFluentHibernate.Entites  
 {  
   class Televizyon  
   {  
     public virtual int televizyonId { get; set; }  
     public virtual string televizyonAd { get; set; }  
     public virtual string televizyonRenk { get; set; }  
     public virtual int televizyonFiyat { get; set; }  
     public virtual Marka televizyonMarka { get; set; }  
   }  
 }  

MarkaMap.cs

 using FluentNHibernate.Mapping;  
 using System;  
 using System.Collections.Generic;  
 using System.Linq;  
 using System.Text;  
 using System.Threading.Tasks;  
 using TelefonFluentHibernate.Entites;  
 namespace TelefonFluentHibernate.Mapping  
 {  
   class MarkaMap : ClassMap <Marka>  
   {  
     public MarkaMap()  
     {  
       Id(x => x.MarkaId);  
       Map(x => x.MarkaAd);  
       Table("Marka");  
     }  
   }  
 }  

TelefonMap.cs

 using FluentNHibernate.Mapping;  
 using System;  
 using System.Collections.Generic;  
 using System.Linq;  
 using System.Text;  
 using System.Threading.Tasks;  
 using TelefonFluentHibernate.Entites;  
 namespace TelefonFluentHibernate.Mapping  
 {  
   class TelefonMap : ClassMap <Telefon>  
   {  
     public TelefonMap()  
     {  
       Id(x => x.telefonId);  
       Map(x => x.telefonAd);  
       Map(x => x.telefonFiyat);  
       Map(x => x.telefonRenk);  
       References(x => x.telefonMarka).Column("MarkaId");  
       Table("Telefon");  
     }  
   }  
 }  

TelevizyonMap.cs

 using FluentNHibernate.Mapping;  
 using System;  
 using System.Collections.Generic;  
 using System.Linq;  
 using System.Text;  
 using System.Threading.Tasks;  
 using TelefonFluentHibernate.Entites;  
 namespace TelefonFluentHibernate.Mapping  
 {  
   class TelevizyonMap : ClassMap <Televizyon>  
   {  
     public TelevizyonMap()  
     {  
       Id(x => x.televizyonId);  
       Map(x => x.televizyonAd);  
       Map(x => x.televizyonFiyat);  
       Map(x => x.televizyonRenk);  
       References(x => x.televizyonMarka).Column("MarkaId");  
       Table("Televizyon");  
     }  
   }  
 }  

NHibernateHelper.cs

 using System;  
 using System.Collections.Generic;  
 using System.Linq;  
 using System.Text;  
 using FluentNHibernate.Cfg;  
 using FluentNHibernate.Cfg.Db;  
 using NHibernate;  
 using NHibernate.Tool.hbm2ddl;  
 using TelefonFluentHibernate.Entites;  
 namespace TelefonFluentHibernate  
 {  
   public class NHibernateHelper  
   {  
     private static ISessionFactory _sessionFactory;  
     private static ISessionFactory SessionFactory  
     {  
       get  
       {  
         if (_sessionFactory == null)  
           InitializeSessionFactory();  
         return _sessionFactory;  
       }  
     }  
     private static void InitializeSessionFactory()  
     {  
       _sessionFactory = Fluently.Configure()  
         .Database(MySQLConfiguration.Standard  
                .ConnectionString(  
                  @"Server=localhost; Port=3306;Database=teknoloji; Uid=root; Pwd=;")  
                .ShowSql()  
         )  
         .Mappings(m =>  
              m.FluentMappings  
                .AddFromAssemblyOf<Program>())  
         .ExposeConfiguration(cfg => new SchemaExport(cfg)  
                         .Create(true, true))  
         .BuildSessionFactory();  
     }  
     public static ISession OpenSession()  
     {  
       return SessionFactory.OpenSession();  
     }  
   }  
 }  

Program.cs

 using NHibernate;  
 using NHibernate.Criterion;  
 using System;  
 using System.Collections.Generic;  
 using System.Linq;  
 using System.Text;  
 using TelefonFluentHibernate.Entites;  
 namespace TelefonFluentHibernate  
 {  
   class Program  
   {  
     static void Main(string[] args)  
     {  
       var telefonNNote4 = new Telefon  
       {  
         telefonAd = "note 4",  
         telefonFiyat = 500,  
         telefonRenk = "beyaz"  
       };  
       var televizyon = new Televizyon  
       {  
         televizyonAd = "tv1",  
         televizyonRenk = "siyah",  
         televizyonFiyat = 1000  
       };  
       var televizyon2 = new Televizyon  
       {  
         televizyonAd = "tv2",  
         televizyonRenk = "beyaz",  
         televizyonFiyat = 1430  
       };  
       var markaSamsung = new Marka  
       {  
         MarkaAd = "samsung"  
       };  
       var markaApple = new Marka  
       {  
         MarkaAd = "apple"  
       };  
       //Create kısmı. Telefon Ekle  
       Ekle<Telefon>(telefonNNote4);  
       //Televizyon ekle  
       Ekle<Televizyon>(televizyon);  
       Ekle<Televizyon>(televizyon2);  
       //Marka ekle  
       Ekle<Marka>(markaSamsung);  
       Ekle<Marka>(markaApple);  
       //Update kısmı. Telefonu güncelle  
       telefonNNote4.telefonMarka = markaSamsung;  
       Guncelle<Telefon>(telefonNNote4);  
       //Televizyonu güncelle  
       televizyon.televizyonMarka = markaApple;  
       televizyon.televizyonRenk = "pembe";  
       Guncelle<Televizyon>(televizyon);  
       televizyon2.televizyonMarka = markaApple;  
       Guncelle<Televizyon>(televizyon2);  
       //Read kısmı   
       Marka marka = Oku("apple");  
       Console.WriteLine("Okunan satir: "+marka.MarkaId+" - "+marka.MarkaAd);  
       //Delete kısmı. Televizyon sil  
       Sil<Televizyon>(televizyon);  
     }  
     private static void Ekle<T>(T yeniKayit)  
     {  
       using (var session = NHibernateHelper.OpenSession())  
       {  
         using (var transaction = session.BeginTransaction())  
         {  
           session.Save(yeniKayit);  
           transaction.Commit();  
           Console.WriteLine("Yeni kayıt eklendi.");  
         }  
       }  
     }  
     private static void Guncelle<T>(T guncelKayit)  
     {  
       using (var session = NHibernateHelper.OpenSession())  
       {  
         using (var transaction = session.BeginTransaction())  
         {  
           session.SaveOrUpdate(guncelKayit);  
           transaction.Commit();  
           Console.WriteLine("Kayit güncellendi. ");  
         }  
       }  
     }  
     private static void Sil<T>(T silKayit)  
     {  
       using (var session = NHibernateHelper.OpenSession())  
       {  
         using (var transaction = session.BeginTransaction())  
         {  
           session.Delete(silKayit);  
           transaction.Commit();  
           Console.WriteLine("Kayit silindi. ");  
         }  
       }  
     }  
     private static Marka Oku(string markaAdi)  
     {  
       using (var session = NHibernateHelper.OpenSession())  
       {  
         Marka markaQuery = (from markaNesnesi in session.QueryOver<Marka>()  
                   where markaNesnesi.MarkaAd == markaAdi  
                   select markaNesnesi).SingleOrDefault();  
         /*IQuery q2 = session.CreateQuery("from Marka WHERE markaAd='" + markaAdi + "';");  
         var markaListesi = q2.List<Marka>();*/  
         Console.WriteLine("Uygun satır bulundu: " + markaQuery.MarkaAd);  
         return markaQuery;  
       }  
     }  
   }  
 }  

Konsol Çıktısı

 alter table telefon drop foreign key FKA4173F7AC8A29C0D  
 alter table Televizyon drop foreign key FK7ADB542AC8A29C0D  
   drop table if exists Marka  
   drop table if exists telefon  
   drop table if exists Televizyon  
   create table Marka (  
     MarkaId INTEGER NOT NULL AUTO_INCREMENT,  
     MarkaAd VARCHAR(255),  
     primary key (MarkaId)  
   )  
   create table telefon (  
     telefonId INTEGER NOT NULL AUTO_INCREMENT,  
     telefonAd VARCHAR(255),  
     telefonFiyat INTEGER,  
     telefonRenk VARCHAR(255),  
     MarkaId INTEGER,  
     primary key (telefonId)  
   )  
   create table Televizyon (  
     televizyonId INTEGER NOT NULL AUTO_INCREMENT,  
     televizyonAd VARCHAR(255),  
     televizyonFiyat INTEGER,  
     televizyonRenk VARCHAR(255),  
     MarkaId INTEGER,  
     primary key (televizyonId)  
   )  
   alter table telefon  
     add index (MarkaId),  
     add constraint FKA4173F7AC8A29C0D  
     foreign key (MarkaId)  
     references Marka (MarkaId)  
   alter table Televizyon  
     add index (MarkaId),  
     add constraint FK7ADB542AC8A29C0D  
     foreign key (MarkaId)  
     references Marka (MarkaId)  
 NHibernate: INSERT INTO telefon (telefonAd, telefonFiyat, telefonRenk, MarkaId)  
 VALUES (?p0, ?p1, ?p2, ?p3);?p0 = 'note 4' [Type: String (6)], ?p1 = 500 [Type:  
 Int32 (0)], ?p2 = 'beyaz' [Type: String (5)], ?p3 = NULL [Type: Int32 (0)]  
 NHibernate: SELECT LAST_INSERT_ID()  
 Yeni kayıt eklendi.  
 NHibernate: INSERT INTO Televizyon (televizyonAd, televizyonFiyat, televizyonRen  
 k, MarkaId) VALUES (?p0, ?p1, ?p2, ?p3);?p0 = 'tv1' [Type: String (3)], ?p1 = 10  
 00 [Type: Int32 (0)], ?p2 = 'siyah' [Type: String (5)], ?p3 = NULL [Type: Int32  
 (0)]  
 NHibernate: SELECT LAST_INSERT_ID()  
 Yeni kayıt eklendi.  
 NHibernate: INSERT INTO Televizyon (televizyonAd, televizyonFiyat, televizyonRen  
 k, MarkaId) VALUES (?p0, ?p1, ?p2, ?p3);?p0 = 'tv2' [Type: String (3)], ?p1 = 14  
 30 [Type: Int32 (0)], ?p2 = 'beyaz' [Type: String (5)], ?p3 = NULL [Type: Int32  
 (0)]  
 NHibernate: SELECT LAST_INSERT_ID()  
 Yeni kayıt eklendi.  
 NHibernate: INSERT INTO Marka (MarkaAd) VALUES (?p0);?p0 = 'samsung' [Type: Stri  
 ng (7)]  
 NHibernate: SELECT LAST_INSERT_ID()  
 Yeni kayıt eklendi.  
 NHibernate: INSERT INTO Marka (MarkaAd) VALUES (?p0);?p0 = 'apple' [Type: String  
  (5)]  
 NHibernate: SELECT LAST_INSERT_ID()  
 Yeni kayıt eklendi.  
 NHibernate: UPDATE telefon SET telefonAd = ?p0, telefonFiyat = ?p1, telefonRenk  
 = ?p2, MarkaId = ?p3 WHERE telefonId = ?p4;?p0 = 'note 4' [Type: String (6)], ?p  
 1 = 500 [Type: Int32 (0)], ?p2 = 'beyaz' [Type: String (5)], ?p3 = 1 [Type: Int3  
 2 (0)], ?p4 = 1 [Type: Int32 (0)]  
 Kayit güncellendi.  
 NHibernate: UPDATE Televizyon SET televizyonAd = ?p0, televizyonFiyat = ?p1, tel  
 evizyonRenk = ?p2, MarkaId = ?p3 WHERE televizyonId = ?p4;?p0 = 'tv1' [Type: Str  
 ing (3)], ?p1 = 1000 [Type: Int32 (0)], ?p2 = 'pembe' [Type: String (5)], ?p3 =  
 2 [Type: Int32 (0)], ?p4 = 1 [Type: Int32 (0)]  
 Kayit güncellendi.  
 NHibernate: UPDATE Televizyon SET televizyonAd = ?p0, televizyonFiyat = ?p1, tel  
 evizyonRenk = ?p2, MarkaId = ?p3 WHERE televizyonId = ?p4;?p0 = 'tv2' [Type: Str  
 ing (3)], ?p1 = 1430 [Type: Int32 (0)], ?p2 = 'beyaz' [Type: String (5)], ?p3 =  
 2 [Type: Int32 (0)], ?p4 = 2 [Type: Int32 (0)]  
 Kayit güncellendi.  
 NHibernate: SELECT this_.MarkaId as MarkaId0_0_, this_.MarkaAd as MarkaAd0_0_ FR  
 OM Marka this_ WHERE this_.MarkaAd = ?p0;?p0 = 'apple' [Type: String (5)]  
 Uygun satır bulundu: apple  
 Okunan satir: 2 - apple  
 NHibernate: DELETE FROM Televizyon WHERE televizyonId = ?p0;?p0 = 1 [Type: Int32  
  (0)]  
 Kayit silindi.  

    Yukarıdaki örnekte kodu yorumları ile birlikte çok rahat anlayacaksınız. Sadece üç tane entity ve üç tane mapping sınıfımız var ve bunlar üzerinde; ekleme, okuma, güncelleme ve silme işlemlerini gerçekleştiriyoruz. Dikkat etmeniz gereken özellikle önemli gördüğüm noktalara değinmek istiyorum. Marka ile Telefon veya Marka ile Televizyon arasındaki ilişki many-to-one olduğundan dolayı; referans olarak many olan tarafta yani Telefonda ve Televizyonda Marka'yı belirtmek zorundayız. "References" kullanımını many olan kısımda yazdığımızı üzerine basa basa söylemek istiyorum aksi taktirde durduk yere hatalar ile karşılaşırsınız. İkinci olarak söylemek istediğim; Marka tipindeki Oku metodu ile markayı okuduğumuz zaman karşımıza çıkan ilk kaydı döndürmek istersek, aşağıdaki şekilde SingleOrDefault yapısını kullanmalıyız.

 Marka markaQuery = (from markaNesnesi in session.QueryOver<Marka>()  
                   where markaNesnesi.MarkaAd == markaAdi  
                   select markaNesnesi).SingleOrDefault();  

   Eğer aradığımız marka adına sahip tüm nesneleri döndürmek istiyorsak, aşağıdaki kod parçasının yardımı ile okuma yapmalıyız.

 IQuery q2 = session.CreateQuery("from Marka WHERE markaAd='" + markaAdi + "';");  
         var markaListesi = q2.List<Marka>();  

   Bugünlük anlatacaklarım bu kadar. Herkese bol kodlu günler.

Referanslar

[1] Create, read, update and delete, http://en.wikipedia.org/wiki/Create,_read,_update_and_delete, Nisan 2, 2015.

[2]Simplify Database Operations with Generic Fluent NHibernate, http://www.codeproject.com/Articles/380022/Simplify-Database-Operations-with-Generic-Fluent-N, Nisan 3, 2015.

[3]Tutorial on NHibernate and FluentNhibernate,  https://thehelios.wordpress.com/2011/07/11/tutorial-on-nhibernate-and-fluentnhibernate/, Nisan 4, 2015.                        


20 Mart 2015 Cuma

Fluent NHibernate Eşleştirme İlişki Çeşitleri


Herkese merhabalar.

   Bugün sizlere eşleştirme çeşitlerinden bahsetmek istiyorum. One-to-many, many-to-one, many-to-many, one-to-one olmak üzere 4 çeşit eşleştirme tipinden bahsedeceğiz. Bu eşleştirme çeşitlerini öğrenirken, geçen hafta anlatmış olduğum terimlerin kullanımını daha iyi anlayacaksınız.

1. One-to-One İlişkisi


    Bu eşleştirme tipinde Türkçe karşılığı ile bire bir ilişkisi vardır. Çok yaygın kurulan bir ilişki çeşidi değildir. Örnek verecek olursak; bir arabanın bir direksiyonu vardır ve o direksiyon da ancak bir arabaya ait olabilir. One-to-one ilişkisini aşağıdaki örnek ile daha iyi anlayacaksınız. Aşağıdaki örnekte; one-to-one ilişkisini sağlamak için iki sınıf da birbirinin özelliğini içermelidir. Tek çocuklu bir aileyi düşünün. Bir annenin sadece bir tane çocuğu vardır; aynı şekilde çocuğun da bir tane annesi vardır.

 public class Anne  
 {  
  public virtual int Id {get;set;}  
  public virtual string isim {get;set;}  
  public virtual string soyisim {get;set;}  
  public virtual Cocuk cocukisim { get; set; }  
 }  
 public class Cocuk  
 {  
  public virtual int Id {get;set;}  
  public virtual string isim {get;set;}  
  public virtual string soyisim {get;set;}  
  public virtual Anne anneisim;  
 }  


 public AnneMap()  
 {  
  HasOne(x =&gt; x.cocukisim)  
    .Cascade.All();  
 }  
 public CocukMap()  
 {  
  References(x =&gt; x.anneisim)  
    .Unique();  
 }  

   Yukarıda one-to-one mapping ilişkisinin genel yapısını görmüş olduk. Mapping sınıflarının içindeki HasOne ve References'ın kullanımına dikkat edin. References terimini kullanıyorsanız; bu ilişkinin karşılıklı birebir ilişkisi olduğunu belirtmek için Unique terimini kullanmayı unutmamalısınız [1].

2. Many-to-One İlişkisi


   Bu ilişki tipinden örneği ile birlikte ikinci hafta bahsetmiştik. Lütfen inceleyiniz. Bu ilişki çeşidini hatırlamak adına örnek verecek olursak; bir sınıf düşünün, bu sınıfın birden fazla öğretmeni olabilir; ama bir öğretmen sadece bir sınıfa ders veriyor şeklinde bir ilişki ayarlamak istediğiniz zaman many-to-one ilişkisi kurulmuş olacak. References teriminin many olan kısımda kullanıldığına dikkat ediniz.


3. One-to-Many İlişkisi


   Many-to-one ilişkisinin tersi şeklinde düşünebiliriz. Aşağıdaki örnek ile daha iyi anlayacaksınız [2].

 public class Sinif  
 {  
   public virtual int Id { get; set; }  
   public virtual string Ad { get; set; }  
   public virtual Ogretmen Ogretmen { get; set; }  
 }  
 public class SinifMap : ClassMap<Sinif>  
 {  
   public Sinif Map()  
   {  
     Id(u => u.Id).GeneratedBy.Identity();  
     Map(u => u.Ad).Nullable();  
     References(x => x.Ogretmen)  
       .Column("OgretmenId")  
       .Not.Nullable();   
   }  
 }  


 public class Ogretmen   
  {   
   public virtual int Id { get; set; }   
   public virtual string Ad { get; set; }   
   public virtual IList&lt;Sinif&gt; Siniflar { get; set; }   
   public Ogretmen()   
   {   
    Siniflar = new List&lt;Sinif&gt;();   
   }   
  }   
  public class OgretmenMap : ClassMap<Ogretmen>  
  {   
   public OgretmenMap()   
   {   
    Id(u =&gt; u.Id).GeneratedBy.Identity();   
    Map(u =&gt; u.Ad).Nullable();   
    HasMany(u =&gt; u.Siniflar)   
     .KeyColumn("OgretmenId")   
     .Inverse()   
     .Cascade.All();   
   }   
  }  

   
   Yukarıdaki örnekte bir öğretmen birden fazla sınıfın dersine girmektedir; ancak her sınıfa bir tane öğretmen girmektedir. Bu yüzden References terimi many olan "SinifMap" sınıfının içinde ve HasMany terimi ise one olan tarafta yazılmıştır [3].

4. Many-to-Many İlişkisi


   Yukarıdaki örnekten devam edecek olursak; bu ilişki tipinde,  bir sınıfın dersine birden fazla öğretmen girebiliyorsa, bir öğretmen de birden fazla sınıfın dersine girebilecektir. Aşağıdaki örnekte ise bir elbiseyi birden fazla kişi sipariş edebilir ve sipariş eden kişi birden fazla elbise sipariş edebilir. Böylelikle many-to-many ilişkisi sağlanmış olur [4].

 class Siparis  
 {  
   public virtual IList<Giysi> Giysiler { get; protected set; }  
 }  
 class Giysi  
 {  
   public virtual IList<Siparis> Siparisler { get; protected set; }  
 }  


 public class SiparisMap : ClassMap<Siparis>  
 {  
   public SiparisMap()  
   {  
     HasManyToMany(x => x.Giysiler)  
       .Cascade.All()  
       .Table("SiparisGiysi");  
   }  
 }  
 public class GiysiMap : ClassMap<Giysi>  
 {  
   public GiysiMap()  
   {  
     HasManyToMany(x => x.Siparisler)  
       .Cascade.All()  
       .Inverse()  
       .Table("SiparisGiysi");  
   }  
 }  


   Bugünlük anlatacaklarım bu kadar, bir sonraki yazımda CRUD işlemlerinden bahsedeceğim, hoşçakalın..

Kaynaklar

[1] Fluent NHibernate One-to-One mapping, http://stackoverflow.com/questions/15724562/fluent-nhibernate-one-to-one-mapping, Mart 18, 2015.

[2]NHIBERBATE 2: MAPPING RELATIONSHIPS AND FLUENT MAPPING, https://www.packtpub.com/books/content/nhibernate-2-mapping-relationships-and-fluent-mapping, Mart 18, 2015.

[3] Fluent NHibernate Has Many Mapping, http://frankdecaire.blogspot.com.tr/2014/04/fluent-nhibernate-hasmany-mapping.html, Mart 19, 2015.

[4]Many to Many Mapping in Fluent NHibernate,  http://www.duncanmcdougall.co.uk/articles/manytomany-fluentnhibernate.html, Mart 19, 2015.

15 Mart 2015 Pazar

Fluent NHibernate ile İlişkisel Nesneler Tasarlamak, Lazy Loading ve Eager Loading


Herkese merhabalar.

Bugün sizlere ilişkisel nesneler tasarlarken bilmeniz gereken bazı kavramlardan ve Fluent NHibernate'de bilmeniz gereken önemli noktalardan ikisi olan Lazy Loading ve Eager Loading'ten bahsetmek istiyorum. 

Id

   Id metodu kullanılarak Id eşleştirilmesi yapılır [1].

 Id(x => x.Id);  

Map edilecek olan Id'nin ismi Id olarak istenmiyorsa Column metodu kullanılarak aşağıdaki şekilde değiştirilebilir [1].

 Id(x => x.Id)  
  .Column("ogrenciId")  
  .GeneratedBy.Assigned();  

Map

Map metodu ile veritabanı ve class'ların eşleşitirlmesi yapılır [1].

 Map(x => x.FirstName);  

References

   Many to one ilişkilendirilmesinde kullanılır. Many tarafında yazılır. Bunun bir örneğini geçen haftaki yazımda incelemiştik. Many olan tarafta yazılır. HasMany/one-to-many, References ilişkilendirilmesinin bir başka türüdür one tarafında yazılırlar [1].

HasManyToMany/many-to-many

Many to many ilişkilendirilmesinde kullanılır [2].

 HasManyToMany(x => x.Kitaplar);  

HasOne/one-to-one

   One to one ilişkilendirilmesinde kullanılır. Bu ilişkilendirilmede HasOne metodunu kullanıyorken foreign key'inizi belirtmek isterseniz; PropertyRef() metodunu kullanabilirsiniz. Eğer References metodunu kullanıyorsanız; çift taraflı eşleştirmenin one-to-one olduğunu göstermek için .Unique() belirtecini kullanmalısınız [1].

 public class ArabaMap : ArabaMap<Araba>  
 {  
   public ArabaMap()  
   {  
     Table( "Araclar.dbo.Araba" );  
     Id( x => x.ArabaId );  
     Map( x => x.Ad );  
     Map( x => x.yil );  
     HasOne( x => x.Direksiyon ).PropertyRef( x => x.Araba);  
   }  
 }  
 public class DireksiyonMap : ClassMap<Direksiyonl>  
 {  
   public DireksiyonMap()  
   {  
     Table( "Araclar.dbo.Direksiyon" );  
     Id( x => x.DireksiyonId );  
     Map( x => x.Cap );  
     Map( x => x.Renk );  
     References( x => x.Araba, "ArabaId" ).Unique();  
   }  
 }  

Yukarıdaki örnekte araba ile direksiyon eşleştirilmesi one-to-one olmuştur ve bu ilişki eşleştirme sınıflarında yukarıdaki şekilde belirtilmelidir. Her arabanın bir tane direksiyonu olur ve o direksiyon ancak bir tane arabaya ait olabilir.

Lazy Loading

   Lazy Loading veya Eager Loading'in etkin olması durumu programın performansını önemli derecede etkilemektedir. Lazy loading, nesneyi oluşturduğuz zaman o nesneye bağlı olan diğer nesneler de çağırdığınızda onunla birlikte gelmemesi durumudur [3]. Çağırılan nesne ile ilgili diğer nesenelerinde beraberinde glmesini istiyorsanız, Lazy Loading etkinken bu durumu belirtmeniz gerekmektedir. Çağrılan ilgili veri persistent, ona bağlı olan veri ise transient olarak geçmektedir. Lazy Loading, olabildiğince minimum veri ile çalışmayı sağlayarak programın performansını arttırmak için kullanılır. Fluent NHibernate'de default olarak Lazy Loading etkindir [4].

   Lazy Loading'in default olarak gelmesini istemiyorsanız aşağıdaki kod parçası ile bu özelliği devre dışı bırakabilirsiniz [3].

 Not.LazyLoad();  

Geçen hafta bahsettiğimiz convention sınıflarında aşağıdaki kod parçası ile Lazy Loading'i devre dışı bırakabilirsiniz.

 var conventions = new Conventions();  
 conventions.DefaultLazyLoad = false;  
 
Eşleştirme sınıfınızın içinde aşağıdaki şekilde Lazy Loading'i devre dışı bırakabilirsiniz.

  using System;
using System.Collections.Generic;
using System.Linq; using System.Text;
using IlkFluentNHibernateProjem.Entites;
using FluentNHibernate.Mapping;
public class OgrenciMap : ClassMap<Ogrenci>
namespace IlkFluentNHibernateProjem.Mapping { { //Constructor
public OgrenciMap() { Id(x => x.Id); Map(x => x.Ad);
References(x => x.OgrenciBolum).Column("BolumId").Not.LazyLoad();
Map(x => x.Soyad); Map(x => x.Donem); Table("Ogrenci"); } }
}

Eager Loading

   Eager loading, nesneyi oluşturduğuz zaman o nesneye bağlı olan diğer nesnelerin de çağırmadığınız halde otomatik olarak onunla birlikte gelmesi durumudur [5]. Gereksiz verilerin de ilgili veri ile gelmesi, programın performansını Lazy Loading kullanımına kıyasla yadsınamayacak kadar düşürecektir [5].

   Bugünlük anlatacaklarım bu kadar, bir sonraki yazımda eşleştirme çeşitlerine yönelik örnekler yapacağız, şimdilik hoşçakalın..

Kaynaklar

[1]  Fluent Mapping, https://github.com/jagregory/fluent-nhibernate/wiki/Fluent-mapping, Mart 11, 2015.

[2] Fluent-nhibernate-create-many-to-many-relationship-table, https://d4dilip.wordpress.com/2011/01/15/fluent-nhibernate-create-many-to-many-relationship-table/, Mart 11, 2015.

[3] Difference between Lazy Loading and Eager Loading, http://www.dotnet-tricks.com/Tutorial/entityframework/RIWW210913-Difference-between-Lazy-Loading-and-Eager-Loading.html, Mart 12, 2015.

[4] Lazy Loading in Fluent NHibernate, http://tempvalue.blogspot.com.tr/2012/05/lazyloading-in-fluent-nhibernate.html, Mart 12, 2015.

[5] Not.LazyLoad - Eager Loading with NHibernate 3.0, http://www.philliphaydon.com/2011/01/not-lazyload-eager-loading-with-nhibernate-3-0/ Mart 13, 2015.

8 Mart 2015 Pazar

Fluent NHibernate Kullanımı ve Convention Sınıfları


Herkese merhabalar.

     Bugün sizlere Fluent NHibernate'in projeye eklenmesi ve nasıl kullanıldığına dair bir örnek göstererek Fluent NHibernate kodlamasına giriş yapacağız. Ayrıca, Fluent NHibernate'te kullanılan Conventionlar üzerinde konuşacağız. Eminim ki bu yazımla Fluent NHibernate'i daha iyi tanımaya başlayacaksınız.

 1. NHibernate Conventionlar'ı

     NHibernate'in desteklediği Convention'lar aşağıda belirttiğim 2 durum için kullanılmaktadır [1].

  • Tablo ve kolon isimleri, eşleştirmede özel olarak belirtilmediği zamanlar
  • Full domain eşleştrimesi

1.1. Tablo ve Kolon İsimlerinin Adlandırılması

       NHibernate'te  tablo ve kolon isimlerini özel olarak belirtmediğiniz durumlarda NHibernate'in isimlendirme stratejisi devreye girerek "sınıf" ve "property"isimleri tablo ve kolon isimlerine verilir, benzer şekilde tersi de gerçekleşmektedir. NHibernate'in iki tane isimlerindirme stratejisi vardır [1].

Default Naming stratejisi: Configuration kısmında isimlendirme stratejisi ile ilgili ekstra bir şey belirtmediğiniz sürece bu strateji devreye girerek isimlendirmeleri birebir gerçekleştirir. Örneğin; kodunuzdaki sınıfınızın ismi "Öğrenci" ise veritabanınızda oluşan tablonun adı da doğrudan doğruya "Öğrenci"olacaktır; çünkü siz configuration kısmında bir şey belirtmediniz ve bu yüzden otomatik olarak "Default Naming" devreye girmiş oldu [1].


Improved Naming stratejisi: Eşleştirme yapılırken sınıf isminizi tablo isminize eşleştiriken alt tire  kullanılır. Örneğin; "BenimEvim" adlı sınıfınız,  "benim_evim" adlı bir tabloya eşleştirilir. Bu isimlendirme stratejisini kullanabilmek için configuration'da aşağıdaki şekilde değişiklik yapmalısınız [1].


 1: cfg.SetNamingStrategy(ImprovedNamingStrategy.Instance); 

Full Domain Eşleştrimesi: Eşleştirmeyi kod ile yapmanın avantajlarından birisi de Conventionlar sayesinde eşleştirmelerinizin otomatik olarak yapılabilmesidir. Bu nasıl olacak ki dediğinizi duyar gibiyim. Şöyle oluyor; sizin sınıflarınızın veritabanı nesneleri ile nasıl ilişkilendirilip eşleştirilmenin yapılacağına karar veren sınıflar var [2]. Şimdilik size bu sınıfları tanıtacağım; ancak ileriki yazılarımda sadece bunları nasıl kullanacağınızı bilmekten öte bu sınıfları kendinize göre uyarlayabilecek hale geleceksiniz ve kendi Convention sınıflarınızı yazabilir hale geleceksiniz. Aşağıda bu Convention sınıf örneklerinin bazılarını tanıtacağım. Daha detaylı bilgi için bu siteyi takip edebilirsiniz.

ColumnNullabilityConvention: Bu sınıf, eğer kolonun boş bırakılabilirliği belirtilmediyse otomatik olarak boş bırakılamama durumunu seçmektedir [2].

 public class ColumnNullabilityConvention  
   : IPropertyConvention, IPropertyConventionAcceptance  
 {  
   public void Accept(IAcceptanceCriteria<IPropertyInspector> criteria)  
   {  
     criteria.Expect(x => x.Nullable, Is.Not.Set);  
   }  
   public void Apply(IPropertyInstance instance)  
   {  
     instance.Not.Nullable();  
   }  
 }  

PrimaryKeyNameConvention: Bu sınıf, primary key olan her kolonun entity adının sonuna Id son ekini alarak isimlendirilmesini sağlar [2].


 public class PrimaryKeyNameConvention : IIdConvention  
 {  
   public void Apply(IIdentityInstance instance)  
   {  
     instance.Column(instance.EntityType.Name + "Id");  
   }  
 }  

StringColumnLengthConvention: String tipindeki kolonun uzunluk sınırı belirtilmediyse bu sınıf sayesinde otomatik olarak uzunluk 100 olarak atanır [2].

 public class StringColumnLengthConvention  
   : IPropertyConvention, IPropertyConventionAcceptance  
 {  
   public void Accept(IAcceptanceCriteria<IPropertyInspector> criteria)  
   {  
     criteria.Expect(x => x.Type == typeof(string))  
       .Expect(x => x.Length == 0);  
   }  
   public void Apply(IPropertyInstance instance)  
   {  
     instance.Length(100);  
   }  
 }  

 2. Fluent NHibernate Projeye Eklenmesi ve İlk Örneğimiz


     Örneğe geçmeden önce Fluent NHibernate ile ilgili dll dosyalarını referans olarak göstermemiz gerekiyor. Bu siteden gidişatı takip ettiğinizde eklenmesinin çok kolay olduğunu göreceksiniz [3].

     Aşağıda gördüğünüz gibi projeye başlamadan önce gerekli dll dosyalarını References kısmına ekledik. Unutmadan şunu da belirtmeliyim ki ben MySql veritabanı kullandığım için MySql.Data.dll dosyasını referans kısmına eklemek zorunda kaldım. Eğer MySql veritabanı kullanıyorsanız bu detayı gözden kaçırmamalısınız.




   Aşağıdaki örnekte, okul isimli veritabanında öğrenci ve bölümü olmak üzere eşleştirme ilişkisi "many to one" olan iki tablo oluşturdum. Şöyle ki bir öğrenci sadece bir bölüme kayıtlı olabiliyorken bir bölüm birden fazla öğrenciye ait olabiliyor. Eşleştirme ilişkilerini önümüzdeki haftalarda çeşitleri ile birlikte detaylı bir şekilde anlatacağım. Bu örnek için many to one'ın ne anlama geldiğini bilmeniz yeterli olacaktır. Solution Explorer'ımızın görünümü aşağıdaki gibidir [4].


Bolum.cs:

 using System;  
 using System.Collections.Generic;  
 using System.Linq;  
 using System.Text;  
 namespace IlkFluentNHibernateProjem.Entites  
 {  
   public class Bolum  
   {  
     public virtual int Id { get; set; }  
     public virtual string BolumAd { get; set; }  
     public virtual string BolumKodu { get; set; }  
   }  
 }  

Ogrenci.cs:

 using System;  
 using System.Collections.Generic;  
 using System.Linq;  
 using System.Text;  
 namespace IlkFluentNHibernateProjem.Entites  
 {  
   public class Ogrenci  
   {  
     public virtual int Id {get; set;}  
     public virtual string Ad { get; set; }  
     public virtual string Soyad { get; set; }  
     public virtual string Donem { get; set; }  
     public virtual Bolum OgrenciBolum { get; set; }  
   }  
 }  

    Bu sınıfta Bolum tipinde "OgrenciBolum" oluşturulmasının sebebi; "OgrenciMap" sayfasında "OgrenciBolum" kısmına Bolum tablosundaki BolumId'yi referans olarak gösterebilme amacı ile yazılmıştır. Böylelikle bir öğrenci eklediğiniz zaman OgrenciBolum kısmına BolumId'yi ekleyecektir.

BolumMap.cs:

 using System;  
 using System.Collections.Generic;  
 using System.Linq;  
 using System.Text;  
 using FluentNHibernate.Mapping;  
 using IlkFluentNHibernateProjem.Entites;  
 namespace IlkFluentNHibernateProjem.Mapping  
 {  
   public class BolumMap : ClassMap<Bolum>  
   {  
     //Constructor  
     public BolumMap()  
     {  
       Id(x => x.Id);  
       Map(x => x.BolumAd);  
       Map(x => x.BolumKodu);  
       Table("Bolum");  
     }  
   }  
 }  

OgrenciMap.cs:

 using System;  
 using System.Collections.Generic;  
 using System.Linq;  
 using System.Text;  
 using FluentNHibernate.Mapping;  
 using IlkFluentNHibernateProjem.Entites;  
 namespace IlkFluentNHibernateProjem.Mapping  
 {  
   public class OgrenciMap : ClassMap<Ogrenci>  
   {  
     //Constructor  
     public OgrenciMap()  
     {  
       Id(x => x.Id);  
       Map(x => x.Ad);  
       Map(x => x.Soyad);  
       Map(x => x.Donem);  
       References(x => x.OgrenciBolum).Column("BolumId");  
       Table("Ogrenci");  
     }  
   }  
 }  

NHibernateHelper.cs:

 using System;  
 using System.Collections.Generic;  
 using System.Linq;  
 using System.Text;  
 using FluentNHibernate.Cfg;  
 using FluentNHibernate.Cfg.Db;  
 using NHibernate;  
 using NHibernate.Tool.hbm2ddl;  
 using IlkFluentNHibernateProjem.Entites;  
 namespace IlkFluentNHibernateProjem  
 {  
   public class NHibernateHelper  
   {  
     private static ISessionFactory _sessionFactory;  
     private static ISessionFactory SessionFactory  
     {  
       get  
       {  
         if (_sessionFactory == null)  
           InitializeSessionFactory();  
         return _sessionFactory;  
       }  
     }  
     private static void InitializeSessionFactory()  
     {  
       _sessionFactory = Fluently.Configure()  
         .Database(MySQLConfiguration.Standard  
                .ConnectionString(  
                  @"Server=localhost; Port=3306;Database=okul; Uid=root; Pwd=;")  
                .ShowSql()  
         )  
         .Mappings(m =>  
              m.FluentMappings  
                .AddFromAssemblyOf<Program>())  
         .ExposeConfiguration(cfg => new SchemaExport(cfg)  
                         .Create(true, true))  
         .BuildSessionFactory();  
     }  
     public static ISession OpenSession()  
     {  
       return SessionFactory.OpenSession();  
     }  
   }  
 }  

   Gerekli konfigürasyonları gerçekleştiren sınıftır. Veritabanı çeşidini değiştirdiğinizde tek yapmanız gereken bu dosyadaki ConnectionString kısmında değişiklik yapmak. İşte Fluent NHibernate'in güzelliklerinden birisi, farklı veritabanları ile çalışmak Fluent NHibernate ile bu kadar basit.

Program.cs:


 using System;  
 using System.Collections.Generic;  
 using System.Linq;  
 using System.Text;  
 using IlkFluentNHibernateProjem.Entites;  
 namespace IlkFluentNHibernateProjem  
 {  
   class Program  
   {  
     static void Main(string[] args)  
     {  
       Bolum bolum;  
       using (var session = NHibernateHelper.OpenSession())   
        {   
          using (var transaction = session.BeginTransaction())  
          {  
            bolum = new Bolum {BolumAd = "Bilgisayar Mühendisliği", BolumKodu = "BIM" };  
            session.Save(bolum);  
            transaction.Commit();  
            Console.WriteLine("Bolum eklendi: " + bolum.BolumAd);  
            session.Close();  
          }   
        }  
       using (var session = NHibernateHelper.OpenSession())  
       {  
         using (var transaction = session.BeginTransaction())  
         {  
           var ogrenci = new Ogrenci { Ad = "Nil Buşra", Soyad = "Özer", Donem = "8", OgrenciBolum = bolum };  
           session.Save(ogrenci);  
           transaction.Commit();  
           Console.WriteLine("Ogrenci kaydedildi: " + ogrenci.Ad + " " + ogrenci.Soyad);  
           session.Close();  
         }  
       }  
     }  
   }  
 }  

   Şunu söylemeliyim ki her işlem için sessionları açıp kapamanız gerekmektedir. Aksi taktirde hatalar ile karşılaşacaksınız.
Arka Planda Çalışan Sorgular:



Program Çalıştıktan Sonra Veritabanı:


    Bu haftalık anlatacaklarım bu kadar, umarım faydalı bir yazı olmuştur. Bir sonraki yazımda; Fluent NHibernate ile ilişkisel nesneler tasarlamak, Lazy Loading ve Eager Loading konularından bahsedeceğim. Şimdilik görüşmek üzere, hoşçakalın..


Kaynaklar

[1] NHibernate Conventions, http://weblogs.asp.net/ricardoperes/nhibernate-conventions, Mart 1, 2015.

[2] Fluent NHibernate conventions-examples, http://marcinobel.com/index.php/fluent-nhibernate-conventions-examples/, Mart 2, 2015.

[3] nuget, https://www.nuget.org/packages/FluentNHibernate/1.3.0.717, Mart 2, 2015.

[4] Start Fluent NHibernate, http://www.codeproject.com/Articles/305493/Start-Fluent-NHibernate, Mart 2, 2015.