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].
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.
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].
StringColumnLengthConvention: String tipindeki kolonun uzunluk sınırı belirtilmediyse bu sınıf sayesinde otomatik olarak uzunluk 100 olarak atanır [2].
2. Fluent NHibernate Projeye Eklenmesi ve İlk Örneğimiz
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
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; }
}
}
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; }
}
}
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");
}
}
}
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");
}
}
}
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 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();
}
}
}
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:
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();
}
}
}
}
}
Program Çalıştıktan Sonra Veritabanı:
[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.
[4] Start Fluent NHibernate, http://www.codeproject.com/Articles/305493/Start-Fluent-NHibernate, Mart 2, 2015.
Fluent NHibernate'in DLL'lerini References klasörüne eklemek için NuGet kullanmak çok rahat oluyor. MySQL için de NuGet kullanılabilir sanırım.. Visual Studio'da projenin üzerine sağ-tıklayıp "Manage NuGet Packages" komutunu verdikten sonra açılan pencereden istediğiniz bileşeni yükleyebiliyorsunuz. Daha önceden yüklenmiş bileşenleri son versiyona güncellemek de bu şekilde çok rahat oluyor.
YanıtlaSilGüzel bir yazı olmuş, teşekkürler.
Muzaffer.