6. ORM NHibernate'e Giriş
Bu bölüm, Java Hibernate çerçevesinin .NET karşılığı olan NHibernate’e kısa bir giriş niteliğindedir. Kapsamlı bir giriş için şu kaynağı okuyabilirsiniz:
Başlık: NHibernate in Action, Yazar: Pierre-Henri Kuaté, Yayınevi: Manning, ISBN-13: 978-1932394924
ORM (Nesne-İlişkisel Eşleştirici), bir veritabanını kullanan programın, açık SQL komutları vermeden ve kullanılan SGBD'in özelliklerini bilmeden bu veritabanını kullanabilmesini sağlayan bir kütüphane grubudur.
Ön Koşullar
[débutant-intermédiaire-avancé] ölçeğinde, bu belge [intermédiaire] bölümünde yer almaktadır. Bu belgeyi anlamak için çeşitli önkoşullar gereklidir; bu önkoşullar, yazdığım bazı belgelerde bulunabilir:
- C# 2008 Dili: [Apprentissage du langage C# Version 3.0 avec le Framework .NET 3.5 ]
- [Spring IoC], URL ve [Spring IoC pour .NET ]'te mevcuttur. Spring.Net ve [Spring.NET | Homepage ] çerçevelerinde kontrol tersine çevirme (Inversion of Control) veya bağımlılık enjeksiyonu (Dependency Injection) kavramlarının temellerini ele alır.
Bu belgenin paragraflarının başında bazen okuma önerileri yer almaktadır. Bu öneriler önceki belgelere atıfta bulunmaktadır.
Araçlar
Bu vaka çalışmasında kullanılan araçlar internette ücretsiz olarak erişilebilir durumdadır. Bunlar şunlardır (Aralık 2011):
- Nhibernate 3.2, [http://nhforge.org/Default.aspx] adresinden erişilebilir
- Spring.net 1.3.2, [http://www.springframework.net] adresinden erişilebilir. Spring.net çerçeve yapısı oldukça kapsamlıdır. Burada, Nhibernate çerçeve yapısının kullanımını kolaylaştırmak için bu çerçeve yapısının sağladığı kütüphaneyi kullanacağız.
- Log4net 1.2.10, [http://logging.apache.org/log4net] adresinde mevcuttur. Bu günlük kaydı çerçevesi, Nhibernate tarafından kullanılmaktadır.
- Nunit 2.5, [http://www.nunit.org/] adresinde mevcuttur. Bu birim test çerçevesi, Java platformu için JUnit çerçevesinin .NET için karşılığıdır.
- SGBD MySQL 5 sürümünün ADO.NET 6.4.4 sürüm sürücüsü, [http://dev.mysql.com/downloads/connector/net] adresinde mevcuttur.
Visual Studio 2010 projeleri için gerekli olan tüm DLL dosyaları, [libnet4] klasöründe bir araya getirilmiştir:
![]() |
6.1. Katmanlı bir .NET mimarisinde NHIBERNATE'in yeri
Bir veritabanı kullanan bir .NET uygulaması, aşağıdaki şekilde katmanlı bir mimariye sahip olabilir:
![]() |
[dao] katmanı, API ve ADO.NET aracılığıyla SGBD ile iletişim kurar (bkz. paragraf 3.3).Önceki mimaride, [ADO.NET] konektörü, SGBD ile bağlantılıdır. Dolayısıyla, [IDbConnection] arayüzünü uygulayan sınıf şudur:
- SGBD ve MySQL için [MySQLConnection] sınıfı
- SGBD ve SQLServer için [SQLConnection] sınıfı
Böylece [dao] katmanı, kullanılan SGBD'e bağımlıdır. Bazı çerçeveler (Linq, Ibatis.net, NHibernate) bu kısıtlamayı, [dao] katmanı ile kullanılan SGBD'in [ADO.NET] konektörü arasına ek bir katman ekleyerek ortadan kaldırır. Burada [NHibernate] çerçeve yapısını kullanacağız.
![]() |
Yukarıda, [dao] katmanı artık [ADO.NET] konektörüne değil, kullanılan [ADO.NET] konektöründen bağımsız bir arayüz sunacak olan NHibernate çerçeve yapısına yöneliktir. Bu mimari, [dao] katmanını değiştirmeden SGBD'i değiştirmeye olanak tanır. Bu durumda yalnızca [ADO.NET] konektörünün değiştirilmesi gerekir.
6.2. Örnek veritabanı
NHibernate ile nasıl çalışılacağını göstermek için, 3.1. paragrafında açıklanan aşağıdaki MySQL [dbpam_nhibernate] veritabanını kullanacağız. Veritabanı yapısının bir SQL dosyasına aktarılması sonucunda şu sonuç elde edilir:
6., 20. ve 36. satırlarda, ID birincil anahtarlarının autoincrement özniteliğine sahip olduğu görülmektedir. Bu, her kayıt eklendiğinde MySQL'in birincil anahtar değerlerini otomatik olarak oluşturacağı anlamına gelir. Geliştiricinin bununla ilgilenmesine gerek yoktur.
6.3. C# örnek projesi
NHibernate'in yapılandırmasını ve kullanımını tanıtmak için aşağıdaki mimariyi kullanacağız:
![]() |
Bir [1] konsol programı, [NHibernate] [3] çerçevesini kullanarak önceki [2] veritabanındaki verileri işleyecektir. Bu da bizi şunları tanıtmaya götürecektir:
- NHibernate yapılandırma dosyaları
- NHibernate'in API'i
C# projesi şu şekilde olacaktır:
![]() |
Proje için gerekli öğeler şunlardır:
- [1] içinde, projenin ihtiyaç duyduğu DLL dosyaları:
- [NHibernate]: NHibernate çerçevesine ait DLL
- [MySql.Data]: SGBD MySQL'in ADO.NET konektörüne ait DLL
- [log4net]: Log4net çerçevesinin DLL'i,
- [2]'te, veritabanı tablolarının görüntü sınıfları
- [3], tüm uygulamayı yapılandıran [App.config] dosyası, buna [NHibernate] çerçeve de dahildir
- [4]'te yer alan test konsol uygulamaları
6.3.1. Veritabanı bağlantısının yapılandırılması
Test mimarisine geri dönelim:
![]() |
Yukarıda, [NHibernate]'in veritabanına erişebilmesi gerekir. Bunun için bazı bilgilere ihtiyacı vardır:
- veritabanını yöneten SGBD (MySQL, SQLServer, Postgres, Oracle, ...). Çoğu SGBD, SQL diline kendilerine özgü uzantılar eklemiştir. SGBD'i bilen NHibernate, bu SGBD'e gönderdiği SQL komutlarını uyarlayabilir. NHibernate, SQL lehçesi kavramını kullanır.
- veritabanına bağlanma parametreleri (veritabanı adı, bağlantının sahibi olan kullanıcının adı, şifresi)
Bu bilgiler [App.config] yapılandırma dosyasına eklenebilir. Aşağıda, MySQL 5 veritabanıyla kullanılacak yapılandırma dosyası yer almaktadır:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<!-- yapılandırma bölümleri -->
<configSections>
<section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler,log4net" />
<section name="hibernate-configuration" type="NHibernate.Cfg.ConfigurationSectionHandler, NHibernate" />
</configSections>
<!-- NHibernate yapılandırması -->
<hibernate-configuration xmlns="urn:nhibernate-configuration-2.2">
<session-factory>
<property name="connection.provider">NHibernate.Connection.DriverConnectionProvider</property>
<!--
<property name="connection.driver_class">NHibernate.Driver.MySqlDataDriver</property>
-->
<property name="dialect">NHibernate.Dialect.MySQL5Dialect</property>
<property name="connection.connection_string">
Server=localhost;Database=dbpam_nhibernate;Uid=root;Pwd=;
</property>
<property name="show_sql">false</property>
<mapping assembly="pam-nhibernate-demos"/>
</session-factory>
</hibernate-configuration>
<!-- Bu bölüm log4net yapılandırma ayarlarını içerir -->
<!-- NOTE IMPORTANTE: Günlükler varsayılan olarak etkin değildir. Bunları program içinde log4net.Config.XmlConfigurator.Configure(); komutuyla etkinleştirmeniz gerekir;
! -->
<log4net>
<!-- Bir çıktı ekleyicisi tanımlayın (günlüklerin gönderileceği yer) -->
<appender name="LogFileAppender" type="log4net.Appender.FileAppender, log4net">
<param name="File" value="log.txt" />
<param name="AppendToFile" value="false" />
<layout type="log4net.Layout.PatternLayout, log4net">
<param name="ConversionPattern" value="%d [%t] %-5p %c [%x] <%X{auth}> - %m%n" />
</layout>
</appender>
<appender name="LogDebugAppender" type="log4net.Appender.DebugAppender, log4net">
<layout type="log4net.Layout.PatternLayout, log4net">
<param name="ConversionPattern" value="%d [%t] %-5p %c [%x] <%X{auth}> - %m%n"/>
</layout>
</appender>
<appender name="ConsoleAppender" type="log4net.Appender.ConsoleAppender, log4net">
<layout type="log4net.Layout.PatternLayout, log4net">
<param name="ConversionPattern" value="%d [%t] %-5p %c [%x] <%X{auth}> - %m%n"/>
</layout>
</appender>
<!-- Kök kategoriyi ayarlayın, varsayılan öncelik düzeyini belirleyin ve ekleyicileri (günlüklerin gönderileceği yer) ekleyin -->
<root>
<priority value="INFO" />
<!--
<appender-ref ref="LogFileAppender" />
<appender-ref ref="LogDebugAppender"/>
-->
<appender-ref ref="ConsoleAppender"/>
</root>
<!-- Belirli ad alanları için seviyeyi belirtin -->
<!-- Seviye şunlar olabilir: ALL, DEBUG, INFO, WARN, ERROR, FATAL, OFF -->
<logger name="NHibernate">
<level value="INFO" />
</logger>
</log4net>
</configuration>
- 4-7. satırlar: [App.config] dosyasındaki yapılandırma bölümlerini tanımlar. 6. satırı ele alalım:
<section name="hibernate-configuration" type="NHibernate.Cfg.ConfigurationSectionHandler, NHibernate" />
Bu satır, [App.config] dosyasında yer alan NHibernate yapılandırma bölümünü tanımlar. Bu bölümün iki özniteliği vardır: name ve type.
- [name] özniteliği, yapılandırma bölümüne ad verir. Bu bölüm, 11-24. satırlardaki <name>...</name> etiketleriyle sınırlandırılmalıdır; burada <hibernate-configuration>...</hibernate-configuration> etiketleri kullanılmaktadır.
- [type=classe,DLL] özniteliği, [name] özniteliği ile tanımlanan bölümü işlemekten sorumlu sınıfın adını ve bu sınıfı içeren DLL özniteliğini belirtir. Burada sınıfın adı [NHibernate.Cfg.ConfigurationSectionHandler]'tir ve DLL [NHibernate.dll] içinde yer almaktadır. Hatırlanacağı üzere, bu DLL, incelenen projenin referanslarının bir parçasıdır.
Şimdi NHibernate'in yapılandırma bölümünü inceleyelim:
<!-- yapılandırma NHibernate -->
<hibernate-configuration xmlns="urn:nhibernate-configuration-2.2">
<session-factory>
<property name="connection.provider">NHibernate.Connection.DriverConnectionProvider</property>
<!--
<property name="connection.driver_class">NHibernate.Driver.MySqlDataDriver</property>
-->
<property name="dialect">NHibernate.Dialect.MySQL5Dialect</property>
<property name="connection.connection_string">
Server=localhost;Database=dbpam_nhibernate;Uid=root;Pwd=;
</property>
<property name="show_sql">false</property>
<mapping assembly="pam-nhibernate-demos"/>
</session-factory>
</hibernate-configuration>
- 2. satır: NHibernate'in yapılandırması bir <hibernate-configuration> etiketinin içindedir. xmlns özniteliği (Xml NameSpace), NHibernate'i yapılandırmak için kullanılan sürümü belirler. Nitekim zaman içinde NHibernate'in yapılandırılma şekli değişmiştir. Burada 2.2 sürümü kullanılmaktadır.
- 3. satır: NHibernate'in yapılandırması burada tamamen <session-factory> etiketinde yer almaktadır (3. ve 14. satırlar). NHibernate oturumu, aşağıdaki şemaya göre bir veritabanıyla çalışmak için kullanılan araçtır:
- oturum açma
- API ve NHibernate yöntemleri aracılığıyla veritabanıyla çalışma
- oturumu kapatma
Oturum, nesneler oluşturabilen bir sınıfı ifade eden genel bir terim olan factory tarafından oluşturulur. 3-14. satırlar bu factory'i yapılandırır.
- 4., 6., 8. ve 9. satırlar: Hedef veritabanına bağlantıyı yapılandırır. Başlıca bilgiler, kullanılan SGBD'in adı, veritabanının adı, kullanıcı kimliği ve şifresidir.
- 4. satır: Bağlantı sağlayıcısını tanımlar; yani veritabanına bağlantı talebinin yapıldığı sağlayıcıyı belirtir. [connection.provider] özelliğinin değeri, bir NHibernate sınıfının adıdır. Bu özellik, kullanılan SGBD'e bağlı değildir.
- 6. satır: Kullanılacak ADO.NET sürücüsü. Bu, belirli bir SGBD (burada MySQL) için özelleştirilmiş bir NHibernate sınıfının adıdır. 6. satır, zorunlu olmadığı için yorum satırı olarak işaretlenmiştir.
- 8. satır: [dialect] özelliği, SGBD ile birlikte kullanılacak SQL lehçesini belirler. Burada SGBD'in lehçesi MySQL'tir.
SGBD'i değiştirirsek, bunun NHibernate lehçesini nasıl bulabiliriz? Önceki C# projesine geri dönelim ve [References] sekmesindeki DLL [NHibernate] öğesine çift tıklayalım:
![]() |
- [1]'te, [Explorateur d'objets] sekmesi, proje tarafından referans verilenler de dahil olmak üzere bir dizi DLL gösterir.
- [2]'te, DLL ve [NHibernate]
- [3]'te, DLL ve geliştirilen [NHibernate] bulunur. Burada tanımlanmış olan çeşitli ad alanları (namespace) yer alır.
- [4]'te, kullanılabilir çeşitli SQL lehçelerini tanımlayan sınıfların bulunduğu [NHibernate.Dialect] ad alanı yer almaktadır.
- [5]'te, SGBD ve MySQL lehçelerinin sınıfı yer almaktadır. 5.
![]() |
- [6]'te, aşağıdaki 6. satırda kullanılan [MySqlDataDriver] sınıfının ad alanı:
<!-- yapılandırma NHibernate -->
<hibernate-configuration xmlns="urn:nhibernate-configuration-2.2">
<session-factory>
<property name="connection.provider">NHibernate.Connection.DriverConnectionProvider</property>
<!--
<property name="connection.driver_class">NHibernate.Driver.MySqlDataDriver</property>
-->
<property name="dialect">NHibernate.Dialect.MySQLDialect</property>
<property name="connection.connection_string">
Server=localhost;Database=dbpam_nhibernate;Uid=root;Pwd=;
</property>
<property name="show_sql">false</property>
<mapping assembly="pam-nhibernate-demos"/>
</session-factory>
</hibernate-configuration>
- 9-11. satırlar: veritabanına bağlantı dizesi. Bu dize "param1=val1;param2=val2; ..." biçimindedir. Bu şekilde tanımlanan parametreler, SGBD sürücüsünün bir bağlantı kurmasını sağlar. Bu bağlantı dizesinin biçimi, kullanılan SGBD sürümüne bağlıdır. Başlıca SGBD sürümlerine ait bağlantı dizeleri, [http://www.connectionstrings.com/] sitesinde bulunabilir. Burada, "Server=localhost;Database=dbpam_nhibernate;Uid=root;Pwd=;" dizesi, SGBD MySQL için bir bağlantı dizesidir. Bu dize şunu belirtir:
- Server=localhost;: SGBD, bağlantı kurmaya çalışan istemciyle aynı makinede bulunuyor
- Database=dbpam_nhibernate; : Hedeflenen MySQL veritabanı
- Uid=root; : Bağlantıyı açan kullanıcı root kullanıcısıdır
- Pwd=;: Bu kullanıcının şifresi yoktur (bu örnekteki özel durum)
- 12. satır: [show_sql] özelliği, NHibernate'in veritabanına gönderdiği SQL komutlarını günlüklerinde gösterip göstermeyeceğini belirtir. Geliştirme aşamasında, NHibernate'in tam olarak ne yaptığını anlamak için bu özelliği [true] olarak ayarlamak yararlıdır.
- 13. satır: <mapping> etiketini anlamak için uygulamanın mimarisine geri dönelim:
![]() |
Konsol programı, ADO.NET konektörünün doğrudan bir istemcisi olsaydı ve çalışan listesini isteseydi, konektöre bir SQL Select komutu çalıştırtırdı ve karşılığında IDataReader türünde bir nesne alırdı; bu nesneyi işleyerek başlangıçta istenen çalışan listesini elde ederdi.
Yukarıda, konsol programı NHibernate’in istemcisidir ve NHibernate, ADO.NET konektörünün istemcisidir. Daha sonra göreceğiz ki, NHibernate'in API'i, konsol programının çalışan listesini talep etmesini sağlayacaktır. NHibernate, bu talebi bir SQL Select emrine dönüştürecek ve bunu ADO.NET konektörüne yürütmesini sağlayacaktır. Bu konektör, programa IDataReader türünde bir nesne döndürecektir. Nhibernate, bu nesneyi kullanarak kendisine istenen çalışan listesini oluşturabilmelidir. Bu, yapılandırma yoluyla mümkün hale getirilir. Veritabanındaki her tabloya bir C# sınıfı eşleştirilmiştir. Böylece, IDataReader tarafından döndürülen [employes] tablosundaki satırlardan yola çıkarak, NHibernate, çalışanları temsil eden nesnelerden oluşan bir liste oluşturabilecek ve bunu konsol programına döndürebilecektir. Bu tablo <--> sınıf ilişkileri yapılandırma dosyalarında oluşturulur. NHibernate, bu ilişkileri tanımlamak için "mapping" terimini kullanır.
Aşağıdaki 13. satıra geri dönelim:
<!-- NHibernate yapılandırması -->
<hibernate-configuration xmlns="urn:nhibernate-configuration-2.2">
<session-factory>
<property name="connection.provider">NHibernate.Connection.DriverConnectionProvider</property>
<!--
<property name="connection.driver_class">NHibernate.Driver.MySqlDataDriver</property>
-->
<property name="dialect">NHibernate.Dialect.MySQL5Dialect</property>
<property name="connection.connection_string">
Server=localhost;Database=dbpam_nhibernate;Uid=root;Pwd=;
</property>
<property name="show_sql">false</property>
<mapping assembly="pam-nhibernate-demos"/>
</session-factory>
</hibernate-configuration>
- satır, tablolar <--> sınıflar yapılandırma dosyalarının [pam-nhibernate-demos] derlemesinde bulunacağını belirtir. Derleme, bir projenin derlenmesi sonucu üretilen yürütülebilir dosya veya DLL'tir. Burada, eşleme dosyaları örnek projenin derlemesine yerleştirilecektir. Bu derlemenin adını öğrenmek için projenin özelliklerine bakmanız gerekir:
![]() |
- [1]'te, proje özellikleri
- [Application] sekmesinde [2], oluşturulacak derleme adı [3].
- Çıkış türü [Application console] [4] olduğu için, projenin derlenmesi sırasında oluşturulan dosyanın adı [pam-nhibernate-demos.exe] olacaktır. Çıkış türü [Bibliothèque de classes] [5] olsaydı, projenin derlenmesi sırasında oluşturulan dosyanın adı [pam-nhibernate-demos.dll] olurdu
- Assembly dosyası, [6] projesinin [bin/Release] klasöründe oluşturulur.
Yukarıdaki açıklamadan, eşleme tabloları <--> sınıflar dosyalarının [pam-nhibernate-demos.exe] [6] dosyasında olması gerektiği anlaşılmaktadır.
6.3.2. 'in <--> sınıflar eşleme tabloları yapılandırması
İncelenen projenin mimarisine geri dönelim:
![]() |
- [1] dosyasındaki konsol programı, NHibernate çerçevesinin API dosyasındaki yöntemleri kullanır. Bu iki blok birbirleriyle nesneler alışverişinde bulunur.
- [2]'te, NHibernate, bir konektör olan NET'in API'ini kullanır. SQL komutlarını hedef SGBD'e gönderir.
Konsol programı, veritabanı tablolarını yansıtan nesneleri işleyecektir. Bu projede, bu nesneler ve bunları veritabanı tablolarıyla birleştiren bağlantılar aşağıdaki [Entites] klasörüne yerleştirilmiştir:
![]() |
- Veritabanındaki her tablo, bir sınıfa ve ikisi arasındaki eşleme dosyasına karşılık gelir
Tablo | Sınıf | Eşleme |
aidatlar | Cotisations.cs | Cotisations.hbm.xml |
çalışanlar | Employe.cs | Employe.hbm.xml |
tazminatlar | Indemnites.cs | Indemnites.hbm.xml |
6.3.2.1. [cotisations] tablosunun eşlemesi
[cotisations] tablosunu ele alalım:
![]() |
|
Bu tablodaki bir satır, aşağıdaki [Cotisations.cs] türündeki bir nesneye yerleştirilebilir:
namespace PamNHibernateDemos {
public class Cotisations {
// otomatik özellikler
public virtual int Id { get; set; }
public virtual int Version { get; set; }
public virtual double CsgRds { get; set; }
public virtual double Csgd { get; set; }
public virtual double Secu { get; set; }
public virtual double Retraite { get; set; }
// üreticiler
public Cotisations() {
}
// ToString
public override string ToString() {
return string.Format("[{0}|{1}|{2}|{3}]", CsgRds, Csgd, Secu, Retraite);
}
}
}
[cotisations] tablosunun her bir sütunu için otomatik bir özellik oluşturulmuştur. NHibernate sınıfının bu sınıfı miras alması ve özelliklerini yeniden tanımlaması (override) gerekeceğinden, bu özelliklerin her biri sanal (virtual) olarak bildirilmelidir. Dolayısıyla bu özellikler sanal olmalıdır.
- satırda, sınıfın [PamNHibernateDemos] ad alanına ait olduğu görülmektedir.
[cotisations] tablosu ile [Cotisations] sınıfı arasında yer alan [Cotisations.hbm.xml] eşleme dosyası şu şekildedir:
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
namespace="PamNHibernateDemos" assembly="pam-nhibernate-demos">
<class name="Cotisations" table="COTISATIONS">
<id name="Id" column="ID" unsaved-value="0">
<generator class="native" />
</id>
<version name="Version" column="VERSION"/>
<property name="CsgRds" column="CSGRDS"/>
<property name="Csgd" column="CSGD"/>
<property name="Retraite" column="RETRAITE"/>
<property name="Secu" column="SECU"/>
</class>
</hibernate-mapping>
- Eşleme dosyası, <hibernate-mapping> etiketinin içinde tanımlanmış bir XML dosyasıdır (2. ve 14. satırlar)
- 4. satır: <class> etiketi, veritabanındaki bir tablo ile bir sınıf arasında bağlantı kurar. Burada, [COTISATIONS] tablosu (table özniteliği) ile [Cotisations] sınıfı (name özniteliği) arasında bağlantı kurar. .NET dosyasında, bir sınıf tam adıyla (ad alanı dahil) ve onu içeren derleme ile tanımlanmalıdır. Bu iki bilgi 3. satırda verilmiştir. İlki (ad alanı), sınıf tanımında bulunabilir. İkincisi (derleme), projenin derleme adıdır. Bu adın nasıl bulunacağını daha önce belirtmiştik.
- 5-7. satırlar: <id> etiketi, [cotisations] tablosunun birincil anahtarının eşlemesini tanımlamak için kullanılır.
- 5. satır: name özniteliği, [cotisations] tablosunun birincil anahtarını barındıracak olan [Cotisations] sınıfındaki alanı belirtir. column özniteliği, [cotisations] tablosunda birincil anahtar görevi gören sütunu belirtir. unsaved-value özniteliği, henüz oluşturulmamış bir birincil anahtarı tanımlamak için kullanılır. Bu değer, NHibernate'in bir [Cotisations] nesnesini [cotisations] tablosuna nasıl kaydedeceğini bilmesini sağlar. Bu nesnenin Id=0 olan bir alanı varsa, SQL INSERT işlemini gerçekleştirir; aksi takdirde SQL UPDATE işlemini gerçekleştirir. unsaved-value'in değeri, [Cotisations] sınıfındaki Id alanının türüne bağlıdır. Burada, bu alanın türü int'tir ve int türünün varsayılan değeri 0'dır. Henüz kaydedilmemiş (dolayısıyla birincil anahtarı olmayan) bir [Cotisations] nesnesinin Id alanı 0 olacaktır. Eğer Id alanı Object türü veya bunun bir türevi olsaydı, unsaved-value=null. yazılırdı
- 6. satır: NHibernate, Id=0 alanına sahip bir [Cotisations] nesnesini kaydetmek istediğinde, veritabanında bir INSERT işlemi gerçekleştirmeli ve bu işlem sırasında kaydın birincil anahtarı için bir değer elde etmelidir. Çoğu SGBD, bu değeri otomatik olarak oluşturmak için kendine özgü bir yönteme sahiptir. <generator> etiketi, birincil anahtarın oluşturulması için kullanılacak mekanizmayı tanımlamak amacıyla kullanılır. <generator class="native"> etiketi, kullanılan SGBD'in varsayılan mekanizmasının kullanılması gerektiğini belirtir. 6.2. paragrafta, üç MySQL tablomuzun birincil anahtarlarının autoincrement özniteliğine sahip olduğunu görmüştük. INSERT işlemleri sırasında, NHibernate, eklenen kaydın ID sütununa bir değer sağlamayacak ve bu değerin MySQL tarafından oluşturulmasına izin verecektir.
- 8. satır: <version> etiketi, kayıtların "sürümlenmesini" sağlayan tablo sütununu (ve buna karşılık gelen sınıf alanını) tanımlamak için kullanılır. Başlangıçta sürüm değeri 1'dir. Her UPDATE işlemi sırasında bu değer artırılır. Öte yandan, herhangi bir UPDATE veya DELETE işlemi, WHERE ID= id AND VERSION=v1. Dolayısıyla bir kullanıcı, yalnızca nesnenin doğru sürümüne sahipse onu değiştirebilir veya silebilir. Aksi takdirde, NHibernate tarafından bir istisna bildirilir.
- 9. satır: <property> etiketi, normal bir sütun eşlemesini tanımlamak için kullanılır (ne birincil anahtar ne de sürüm sütunu). Böylece 9. satır, [COTISATIONS] tablosundaki CSGRDS sütununun, [Cotisations] sınıfındaki CsgRds özelliğiyle ilişkilendirildiğini gösterir.
6.3.2.2. [indemnites] tablosunun eşlemesi
[indemnites] tablosunu ele alalım:
![]() |
|
Bu tablodaki bir satır, aşağıdaki gibi [Indemnites] türünde bir nesneye yerleştirilebilir:
namespace PamNHibernateDemos {
public class Indemnites {
// otomatik özellikler
public virtual int Id { get; set; }
public virtual int Version { get; set; }
public virtual int Indice { get; set; }
public virtual double BaseHeure { get; set; }
public virtual double EntretienJour { get; set; }
public virtual double RepasJour { get; set; }
public virtual double IndemnitesCp { get; set; }
// üreticiler
public Indemnites() {
}
// kimlik
public override string ToString() {
return string.Format("[{0}|{1}|{2}|{3}|{4}]", Indice, BaseHeure, EntretienJour, RepasJour, IndemnitesCp);
}
}
}
[indemnites] <--> [Indemnites] sınıfı eşleme tablosu dosyası şu şekilde olabilir (Indemnites.hbm.xml):
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
namespace="PamNHibernateDemos" assembly="pam-nhibernate-demos">
<class name="Indemnites" table="INDEMNITES">
<id name="Id" column="ID" unsaved-value="0">
<generator class="native" />
</id>
<version name="Version" column="VERSION"/>
<property name="Indice" column="INDICE" unique="true"/>
<property name="BaseHeure" column="BASE_HEURE" />
<property name="EntretienJour" column="ENTRETIEN_JOUR" />
<property name="RepasJour" column="REPAS_JOUR" />
<property name="IndemnitesCp" column="INDEMNITES_CP" />
</class>
</hibernate-mapping>
Burada, daha önce açıklanan eşleme dosyasına göre yeni bir şey yoktur. Tek fark 9. satırda yer almaktadır. unique="true" özniteliği, [indemnites] tablosunda [INDICE] sütunu üzerinde bir tekillik kısıtlaması olduğunu gösterir: [INDICE] sütununda aynı değere sahip iki satır bulunamaz.
6.3.2.3. [employes] tablosunun eşlemesi
[employes] tablosunu ele alalım:
![]() |
|
Önceki tablolara kıyasla yeni olan özellik, bir yabancı anahtarın varlığıdır: [INDEMNITE_ID] sütunu, [INDEMNITES] tablosundaki [ID] sütununa ilişkin bir yabancı anahtardır. Bu alan, çalışanın tazminatlarının hesaplanmasında kullanılacak [INDEMNITES] tablosundaki satırı referans alır.
[Employe] sınıfı , [employes] tablosunun görüntüsü şu şekilde olabilir:
namespace PamNHibernateDemos {
public class Employe {
// otomatik özellikler
public virtual int Id { get; set; }
public virtual int Version { get; set; }
public virtual string SS { get; set; }
public virtual string Nom { get; set; }
public virtual string Prenom { get; set; }
public virtual string Adresse { get; set; }
public virtual string Ville { get; set; }
public virtual string CodePostal { get; set; }
public virtual Indemnites Indemnites { get; set; }
// oluşturucular
public Employe() {
}
// ToString
public override string ToString() {
return string.Format("[{0}|{1}|{2}|{3}|{4}|{5}|{6}]", SS, Nom, Prenom, Adresse, Ville, CodePostal, Indemnites);
}
}
}
[Employe.hbm.xml] eşleme dosyası şu şekilde olabilir:
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
namespace="PamNHibernateDemos" assembly="pam-nhibernate-demos">
<class name="Employe" table="EMPLOYES">
<id name="Id" column="ID" unsaved-value="0">
<generator class="native" />
</id>
<version name="Version" column="VERSION"/>
<property name="SS" column="SS"/>
<property name="Nom" column="NOM"/>
<property name="Prenom" column="PRENOM"/>
<property name="Adresse" column="ADRESSE"/>
<property name="Ville" column="VILLE"/>
<property name="CodePostal" column="CP"/>
<many-to-one name="Indemnites" column="INDEMNITE_ID" cascade="save-update" lazy="false"/>
</class>
</hibernate-mapping>
Yenilik, 15. satırda yeni bir etiket olan <many-to-one>'ın ortaya çıkmasıyla ilgilidir. Bu etiket, [INDEMNITE_ID] tablosundaki bir yabancı anahtar sütununu, [EMPLOYES] tablosundan [Employe] sınıfının [Indemnites] özelliğine eşlemek için kullanılır:
namespace PamNHibernateDemos {
public class Employe {
// otomatik özellikler
..
public virtual Indemnites Indemnites { get; set; }
...
}
}
[EMPLOYES] tablosunda, [INDEMNITES] tablosundaki [ID] sütununa referans veren [INDEMNITE_ID] yabancı anahtarı bulunmaktadır. [EMPLOYES] tablosundaki birden fazla (many) satır, [INDEMNITES] tablosundaki tek bir (one) satıra başvurabilir. Bu nedenle etiket adı <many-to-one> olarak belirlenmiştir. Bu etiket burada aşağıdaki özniteliklere sahiptir:
- column: [EMPLOYES] tablosunda, [INDEMNITES] tablosuna yabancı anahtar olarak işlev gören sütunun adını belirtir
- name: Bu sütunla ilişkili [Employe] sınıfının özelliğini belirtir. Bu özelliğin türü, zorunlu olarak yabancı anahtarın hedef tablosuyla ilişkili sınıftır; burada bu, [INDEMNITES] tablosudur. Bu sınıfın, daha önce açıklanan [Indemnites] sınıfı olduğu bilinmektedir. Yukarıdaki 5. satırda da bu durum yansıtılmaktadır. Bu, NHibernate sınıfı veritabanından bir [Employe] nesnesini geri getirdiğinde, buna eşlik eden [Indemnites] nesnesini de geri getireceği anlamına gelir.
- cascade: Bu öznitelik çeşitli değerler alabilir:
- save-update: [Employe] nesnesi üzerinde yapılan bir ekleme (save) veya güncelleme (update) işlemi, bu nesnenin içerdiği [Indemnites] nesnesine de yayılmalıdır.
- delete: [Employe] nesnesinin silinmesi, içerdiği [Indemnites] nesnesine yayılmalıdır.
- all: Ekleme (save), güncelleme (update) ve silme (delete) işlemlerini yansıtır.
- none: hiçbir işlemi yaymaz
Son olarak, [App.config] dosyasında NHibernate'in yapılandırmasını hatırlayalım:
<!-- yapılandırma NHibernate -->
<hibernate-configuration xmlns="urn:nhibernate-configuration-2.2">
<session-factory>
<property name="connection.provider">NHibernate.Connection.DriverConnectionProvider</property>
<!--
<property name="connection.driver_class">NHibernate.Driver.MySqlDataDriver</property>
-->
<property name="dialect">NHibernate.Dialect.MySQL5Dialect</property>
<property name="connection.connection_string">
Server=localhost;Database=dbpam_nhibernate;Uid=root;Pwd=;
</property>
<property name="show_sql">false</property>
<mapping assembly="pam-nhibernate-demos"/>
</session-factory>
</hibernate-configuration>
- satır, *.hbm.xml eşleme dosyalarının [pam-nhibernate-demos] derlemesinde bulunacağını belirtir. Bu, varsayılan olarak yapılmaz. C# projesinde yapılandırılması gerekir:
![]() |
- [1]'te, bir eşleme dosyasının özellikleri seçilir
- [2]'e, oluşturma eylemi [Ressource incorporée] [3] olmalıdır. Bu, projenin oluşturulması sırasında eşleme dosyasının oluşturulan derlemeye dahil edilmesi gerektiği anlamına gelir.
6.4. NHibernate'ten API'e
Örnek projemizin mimarisine geri dönelim:
![]() |
Önceki paragraflarda, NHibernate dosyasını iki şekilde yapılandırdık:
- [App.config]'te, veritabanına bağlantıyı yapılandırdık
- veritabanındaki her tablo için, o tablonun görüntü sınıfını ve sınıftan tabloya ve tablodan sınıfa geçişi sağlayan eşleme dosyasını yazdık.
Şimdi NHibernate'in veritabanı verilerini işlemek için sunduğu yöntemleri keşfetmemiz gerekiyor: ekleme, güncelleme, silme, liste.
6.4.1. SessionFactory nesnesi
Tüm NHibernate işlemleri bir oturum içinde gerçekleştirilir. Tipik bir NHibernate işlem dizisi şöyledir:
- NHibernate oturumu açma
- oturumda bir işlem başlatma
- oturumla kalıcılık işlemleri yapmak (Load, Get, Find, CreateQuery, Save, SaveOrUpdate, Delete)
- işlemi onaylamak (commit) veya geri almak (rollback)
- NHibernate oturumunu kapatmak
Bir oturum, [SessionFactory] türündeki bir fabrikadan alınır. Bu fabrika, [App.config] yapılandırma dosyasındaki <session-factory> etiketiyle yapılandırılan fabrikadır:
<!-- yapılandırma NHibernate -->
<hibernate-configuration xmlns="urn:nhibernate-configuration-2.2">
<session-factory>
<property name="connection.provider">NHibernate.Connection.DriverConnectionProvider</property>
<!--
<property name="connection.driver_class">NHibernate.Driver.MySqlDataDriver</property>
-->
<property name="dialect">NHibernate.Dialect.MySQL5Dialect</property>
<property name="connection.connection_string">
Server=localhost;Database=dbpam_nhibernate;Uid=root;Pwd=;
</property>
<property name="show_sql">false</property>
<mapping assembly="pam-nhibernate-demos"/>
</session-factory>
</hibernate-configuration>
C# kodunda, SessionFactory şu şekilde elde edilebilir:
ISessionFactory sessionFactory = new Configuration().Configure().BuildSessionFactory();
Configuration sınıfı, NHibernate çerçevesine ait bir sınıftır. Yukarıdaki komut, [App.config] içindeki NHibernate yapılandırma bölümünü kullanır. Elde edilen [ISessionFactory] nesnesi, hedef veritabanına bağlantı kurmak için gerekli şu bilgileri içerir:
- hedef veritabanına bağlantı kurmak için gerekli bilgiler
- veritabanı tabloları ile NHibernate tarafından işlenen kalıcı sınıflar arasındaki eşleme dosyaları.
6.4.2. NHibernate oturumu
SessionFactory oluşturulduktan sonra (bu işlem tek seferliktir), NHibernate kalıcılık işlemlerini gerçekleştirmek için gerekli oturumları elde edebiliriz. Yaygın olarak kullanılan bir kod şöyledir:
try{
// oturum açma
using (ISession session = sessionFactory.OpenSession())
{
// işlem başlangıcı
using (ITransaction transaction = session.BeginTransaction())
{
........................ opérations de persistance
// işlemin onaylanması
transaction.Commit();
}
}
}catch (Exception ex){
....
}
- 3. satır: Bir using cümlesi içinde SessionFactory'ten bir oturum oluşturulur. using cümlesinden çıkıldığında oturum otomatik olarak kapatılır. using cümlesi olmasaydı, oturumu açıkça kapatmak gerekirdi (session.Close()).
- 6. satır: Kalıcılık işlemleri bir işlem bloğu içinde gerçekleştirilecektir. Ya hepsi başarılı olur ya da hiçbiri başarılı olmaz. using, cümlesi içinde işlem, bir Commit ile onaylanır (10. satır). İşlem sırasında bir kalıcılık işlemi bir istisna oluşturursa, using'ten çıkıldığında işlem otomatik olarak bir Rollback ile geçersiz kılınır.
- 1. ve 13. satırlardaki try / catch bloğu, try bloğu içindeki kod (oturum, işlem, kalıcılık) tarafından atılabilecek olası bir istisnayı yakalamaya olanak tanır.
6.4.3. ISession arayüzü
Şimdi, bir NHibernate oturumu tarafından uygulanan ISession arayüzünün bazı yöntemlerini tanıtacağız:
oturumda bir işlem başlatır ITransaction tx=session.BeginTransaction(); | |
oturumu boşaltır. Oturumda bulunan nesneler serbest kalır. session.Clear(); | |
oturumu kapatır. Oturumda bulunan nesneler veritabanıyla senkronize edilir. Bu senkronizasyon işlemi, bir işlemin sonunda da gerçekleştirilir. İkinci durum daha yaygındır. session.Close(); | |
daha sonra çalıştırılmak üzere bir HQL (Hibernate Query Language) sorgusu oluşturur. IQuery query=session.createQuery("select e from Employe e); | |
bir nesneyi siler. Bu nesne oturuma ait olabilir (bağlı) veya olmayabilir (bağlantısız). Oturumun veritabanıyla senkronizasyonu sırasında, bu nesne üzerinde bir SQL DELETE işlemi gerçekleştirilir. // BD'ten bir çalışan yüklenir Çalışan e = session.Get<Çalışan>(143); // siliniyor session.Delete(e); | |
oturumun veritabanıyla senkronizasyonunu zorlar. Oturumun içeriği değişmez. session.Flush(); | |
veritabanından id birincil anahtarına sahip T nesnesini arar. Bu nesne yoksa, işaretçiyi null yapar. // BD'ten bir çalışanı yükler Employe e = session.Get<Employe>(143); | |
obj nesnesini oturuma ekler. Bu nesne, Save'ten önce bir birincil anahtara sahip değildir. Save'ten sonra birincil anahtarı olur. Oturum senkronizasyonu sırasında, veritabanında bir SQL INSERT işlemi gerçekleştirilecektir. // bir çalışan oluşturulur Çalışan e = new Çalışan(){...}; // kaydediliyor e = session.Save(e); | |
obj'nin birincil anahtarı yoksa Save işlemini, zaten birincil anahtarı varsa Update işlemini gerçekleştirir. | |
veritabanındaki obj nesnesini günceller. Ardından veritabanında bir SQL UPDATE işlemi gerçekleştirilir. // BD'ten bir çalışan yüklenir Çalışan e = session.Get<Çalışan>(143); // adını değiştiriyoruz e.Nom=...; // veritabanında güncellenir session.Update(e); |
6.4.4. IQuery arayüzü
IQuery arayüzü, veritabanından veri almak için sorgu yapmayı sağlar. Bir örneğini nasıl oluşturacağımızı gördük:
createQuery yönteminin parametresi, HQL (Hibernate Query Language) sorgusudur; bu dil, SQL diline benzer ancak tablolar yerine sınıfları sorgular. Yukarıdaki sorgu, tüm çalışanların listesini ister. İşte birkaç HQL sorgu örneği:
select e from Employe e where e.Nom like 'A%'
select e from Employe order by e.Nom asc
select e from Employe e where e.Indemnites.Indice=2
Şimdi IQuery arayüzünün bazı yöntemlerini tanıtacağız:
sorgu sonucunu T nesnelerinden oluşan bir liste biçiminde döndürür IList<Çalışan> çalışanlar=session.createQuery("select e from Çalışan e order by e.Nom asc").List<Çalışan>(); | |
sorgu sonucunu, listenin her bir öğesinin Select sorgusunun bir satır sonucunu nesne tablosu biçiminde temsil ettiği bir liste olarak döndürür. IList satırlar=session.createQuery("select e.Nom, e.Prenom, e.SS from Çalışan").List(); satırlar[i][j], i satırındaki j sütununu bir object türünde temsil eder. Dolayısıyla satırlar[10][1], bir kişinin adını temsil eden bir object türüdür. Verileri tam türlerinde almak için genellikle tür dönüştürme işlemleri gerekir. | |
sorgu sonucundaki ilk nesneyi döndürür Employe e=session.createQuery("select e from Employe e where e.Nom='MARTIN'").UniqueResult<Employe>(); |
Bir HQL sorgusu şu şekilde yapılandırılabilir:
- satırdaki HQL sorgusunda, :num, sorgu çalıştırılmadan önce bir değer alması gereken bir parametredir. Yukarıda, bunun için SetString yöntemi kullanılmaktadır. IQuery arayüzü, bir parametreye değer atamak için çeşitli Set yöntemlerine sahiptir:
- - SetBoolean(string name, bool value)
- - SetSingle(string name, single value)
- - SetDouble(string name, double value)
- - SetInt32(string name, int32 value)
- ..
6.5. Bazı kod örnekleri
Aşağıdaki örnekler, daha önce incelenen ve aşağıda özetlenen mimariye dayanmaktadır. Veritabanı, daha önce de sunulan MySQL [dbpam_nhibernate] veritabanıdır. Örnekler, [1] konsol programlarıdır ve NHibernate [3] çerçeve yapısını kullanarak [2] veritabanını işler.
![]() |
Aşağıdaki örneklerin yer aldığı C# projesi, daha önce tanıtılan projedir:
![]() |
- [1]'te, projenin ihtiyaç duyduğu DLL'ler:
- [NHibernate]: NHibernate çerçevesinin DLL dosyası
- [MySql.Data]: SGBD MySQL 5'in ADO.NET konektörüne ait DLL
- [log4net]: DLL'in, [2]'te günlük dosyaları oluşturmaya yarayan bir araç
- [2]'te, veritabanı tablolarının görüntü sınıfları
- [3]'te, tüm uygulamayı yapılandıran [App.config] dosyası, buna [NHibernate]
- [4]'te yer alan çerçeve dahil olmak üzere, test amaçlı konsol uygulamaları. Bu uygulamaların bir kısmını burada tanıtacağız.
6.5.1. Veritabanının içeriğini alma
[ShowDataBase.cs] programı, veritabanının içeriğini görüntülemeye olanak tanır:
using System;
using System.Collections;
using System.Collections.Generic;
using NHibernate;
using NHibernate.Cfg;
namespace PamNHibernateDemos
{
public class ShowDataBase
{
private static ISessionFactory sessionFactory = null;
// ana program
static void Main(string[] args)
{
// fabrika başlatma NHibernate
sessionFactory = new Configuration().Configure().BuildSessionFactory();
try
{
// veritabanı içeriğinin görüntülenmesi
Console.WriteLine("Affichage base -------------------------------------");
ShowDataBase1();
}
catch (Exception ex)
{
// istisna görüntüleniyor
Console.WriteLine(string.Format("L'erreur suivante s'est produite : [{0}]", ex.ToString()));
}
finally
{
if (sessionFactory != null)
{
sessionFactory.Close();
}
}
// klavye girişi bekleniyor
Console.ReadLine();
}
// test1
static void ShowDataBase1()
{
// oturum açma
using (ISession session = sessionFactory.OpenSession())
{
// işlem başlangıcı
using (ITransaction transaction = session.BeginTransaction())
{
// çalışan listesi alınır
IList<Employe> employes = session.CreateQuery(@"select e from Employe e order by e.Nom asc").List<Employe>();
// görüntüleniyor
Console.WriteLine("--------------- liste des employés");
foreach (Employe e in employes)
{
Console.WriteLine(e);
}
// tazminat listesi alınır
IList<Indemnites> indemnites = session.CreateQuery(@"select i from Indemnites i order by i.Indice asc").List<Indemnites>();
// görüntüleniyor
Console.WriteLine("--------------- liste des indemnités");
foreach (Indemnites i in indemnites)
{
Console.WriteLine(i);
}
// prim listesi alınır
Cotisations cotisations = session.CreateQuery(@"select c from Cotisations c").UniqueResult<Cotisations>();
Console.WriteLine("--------------- tableau des taux de cotisations");
Console.WriteLine(cotisations);
// işlemi kaydet
transaction.Commit();
}
}
}
}
}
Açıklamalar:
- 19. satır: SessionFactory nesnesi oluşturulur. Session nesnelerini almamızı sağlayacak olan da budur.
- 24. satır: veritabanının içeriği görüntülenir
- 31-37. satırlar: SessionFactory, try.'in finally cümlesinde kapatılır
- 43. satır: veritabanının içeriğini görüntüleyen yöntem
- 46. satır: SessionFactory'ten bir Session elde edilir.
- 49. satır: Bir işlem başlatılır
- 52. satır: Çalışan listesini almak için HQL sorgusu. Employe varlığını Indemnite varlığına bağlayan yabancı anahtar sayesinde, her çalışanın tazminatı da elde edilir.
- 60. satır: Tazminat listesini almak için HQL sorgusu.
- 68. satır: Katkı payları tablosundaki tek satırı almak için HQL sorgusu.
- 72. satır: işlemin sonu
- satır 73: satır 49'daki using Itransaction ifadesinin sonu – işlem otomatik olarak kapatılır
- satır 74: satır 46'daki using Isession'ın sonu – oturum otomatik olarak kapatılır.
Ekranda görüntülenen sonuç:
- ve 4. satırlarda, bir çalışanı sorguladığımızda, onun tazminat bilgisini de aldığımız görülmektedir.
6.5.2. Veritabanına veri ekleme
[FillDataBase.cs] programı, verileri veritabanına eklemeye olanak tanır:
using System;
using System.Collections;
using System.Collections.Generic;
using NHibernate;
using NHibernate.Cfg;
namespace PamNHibernateDemos
{
public class FillDataBase
{
private static ISessionFactory sessionFactory = null;
// ana program
static void Main(string[] args)
{
// fabrika başlatma NHibernate
sessionFactory = new Configuration().Configure().BuildSessionFactory();
try
{
// veritabanının içeriğinin silinmesi
Console.WriteLine("Effacement base -------------------------------------");
ClearDataBase1();
Console.WriteLine("Affichage base -------------------------------------");
ShowDataBase();
Console.WriteLine("Remplissage base -------------------------------------");
FillDataBase1();
Console.WriteLine("Affichage base -------------------------------------");
ShowDataBase();
}
catch (Exception ex)
{
// istisna görüntüleniyor
Console.WriteLine(string.Format("L'erreur suivante s'est produite : [{0}]", ex.ToString()));
}
finally
{
if (sessionFactory != null)
{
sessionFactory.Close();
}
}
// klavye girişi bekleniyor
Console.ReadLine();
}
// test1
static void ShowDataBase()
{
// önceki örneğe bakın
}
// ClearDataBase1
static void ClearDataBase1()
{
// oturum açma
using (ISession session = sessionFactory.OpenSession())
{
// işlem başlangıcı
using (ITransaction transaction = session.BeginTransaction())
{
// çalışan listesi alınır
IList<Employe> employes = session.CreateQuery(@"select e from Employe e").List<Employe>();
// tüm çalışanlar siliniyor
Console.WriteLine("--------------- suppression des employés associés");
foreach (Employe e in employes)
{
session.Delete(e);
}
// tazminat listesi alınır
IList<Indemnites> indemnites = session.CreateQuery(@"select i from Indemnites i").List<Indemnites>();
// tazminatlar siliniyor
Console.WriteLine("--------------- suppression des indemnités");
foreach (Indemnites i in indemnites)
{
session.Delete(i);
}
// primlerin listesini alır
Cotisations cotisations = session.CreateQuery(@"select c from Cotisations c").UniqueResult<Cotisations>();
Console.WriteLine("--------------- suppression des taux de cotisations");
if (cotisations != null)
{
session.Delete(cotisations);
}
// işlemi kaydet
transaction.Commit();
}
}
}
// FillDataBase
static void FillDataBase1()
{
// oturum açma
using (ISession session = sessionFactory.OpenSession())
{
// işlemin başlangıcı
using (ITransaction transaction = session.BeginTransaction())
{
// iki tazminat oluşturuluyor
Indemnites i1 = new Indemnites() { Id = 0, Indice = 1, BaseHeure = 1.93, EntretienJour = 2, RepasJour = 3, IndemnitesCp = 12 };
Indemnites i2 = new Indemnites() { Id = 0, Indice = 2, BaseHeure = 2.1, EntretienJour = 2.1, RepasJour = 3.1, IndemnitesCp = 15 };
// iki çalışan oluşturuluyor
Employe e1 = new Employe() { Id = 0, SS = "254104940426058", Nom = "Jouveinal", Prenom = "Marie", Adresse = "5 rue des oiseaux", Ville = "St Corentin", CodePostal = "49203", Indemnites = i1 };
Employe e2 = new Employe() { Id = 0, SS = "260124402111742", Nom = "Laverti", Prenom = "Justine", Adresse = "La Brûlerie", Ville = "St Marcel", CodePostal = "49014", Indemnites = i2 };
// prim oranları oluşturuluyor
Cotisations cotisations = new Cotisations() { Id = 0, CsgRds = 3.49, Csgd = 6.15, Secu = 9.39, Retraite = 7.88 };
// her şey kaydediliyor
session.Save(e1);
session.Save(e2);
session.Save(cotisations);
// işlemi onaylama
transaction.Commit();
}
}
}
}
}
Açıklamalar
- 19. satır: SessionFactory oluşturulur
- 37-43. satırlar: try programının finally cümlesinde kapatılır
- 55. satır: Veritabanını boşaltan ClearDataBase1 yöntemi. İşleyiş şu şekildedir:
- tüm çalışanlar (64. satır) bir listeye alınır
- bunlar tek tek silinir (satır 67-70)
- 93. satır: FillDataBase1 yöntemi, veritabanına bazı veriler ekler
- iki Indemnites nesnesi oluşturulur (satır 102, 103)
- bu tazminatlara sahip iki çalışan oluşturulur (satır 105, 106)
- 108. satırda bir Cotisations nesnesi oluşturulur.
- 110. ve 111. satırlar: İki "Çalışan" varlığı veritabanına kaydedilir
- 112. satır: Cotisations varlığı da sırayla kalıcı hale getirilir
- 102. ve 103. satırlardaki Indemnités varlıklarının kaydedilmemiş olması şaşırtıcı gelebilir. Aslında bunlar, Employe varlıklarıyla aynı anda kaydedilmiştir. Bunu anlamak için Employe varlığının eşlemesine geri dönelim:
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
namespace="PamNHibernateDemos" assembly="pam-nhibernate-demos">
<class name="Employe" table="EMPLOYES">
<id name="Id" column="ID" unsaved-value="0">
<generator class="native" />
</id>
<version name="Version" column="VERSION"/>
<property name="SS" column="SS"/>
<property name="Nom" column="NOM"/>
<property name="Prenom" column="PRENOM"/>
<property name="Adresse" column="ADRESSE"/>
<property name="Ville" column="VILLE"/>
<property name="CodePostal" column="CP"/>
<many-to-one name="Indemnites" column="INDEMNITE_ID" cascade="save-update" lazy="false"/>
</class>
</hibernate-mapping>
Employe varlığını Indemnites varlığına bağlayan yabancı anahtar ilişkisini eşleyen 15. satırda cascade="save-update" özniteliği bulunmaktadır; bu da Employe varlığının "save " ve "update" işlemlerinin, iç varlık olan Indemnites'e yayılmasına neden olur.
Ekranda görüntülenen sonuç:
Effacement base -------------------------------------
--------------- suppression des employés et des indemnités associées
--------------- suppression des indemnités restantes
--------------- suppression des taux de cotisations
Affichage base -------------------------------------
--------------- liste des employés
--------------- liste des indemnités
--------------- tableau des taux de cotisations
Remplissage base -------------------------------------
Affichage base -------------------------------------
--------------- liste des employés
[254104940426058|Jouveinal|Marie|5 rue des oiseaux|St Corentin|49203|[2|2,1|2,1|3,1|15]]
[260124402111742|Laverti|Justine|La Brûlerie|St Marcel|49014|[1|1,93|2|3|12]]
--------------- liste des indemnités
[1|1,93|2|3|12]
[2|2,1|2,1|3,1|15]
--------------- tableau des taux de cotisations
[3,49|6,15|9,39|7,88]
6.5.3. Çalışan Arama
[Program.cs] programı, veritabanındaki verilere erişim ve bu verilerin işlenmesini gösteren çeşitli yöntemler içerir. Bunlardan birkaçını aşağıda sunuyoruz.
[FindEmployee] yöntemi, bir çalışanı sosyal güvenlik numarasına göre bulmaya olanak tanır:
// FindEmployee
static void FindEmployee() {
try {
// oturum açma
using (ISession session = sessionFactory.OpenSession()) {
// işlem başlatma
using (ITransaction transaction = session.BeginTransaction()) {
// çalışanı numarasına göre arama SS
String numSecu = "254104940426058";
IQuery query = session.CreateQuery(@"select e from Employe e where e.SS=:numSecu");
Employe employe = query.SetString("numSecu", numSecu).UniqueResult<Employe>();
if (employe != null) {
Console.WriteLine("Employe[" + numSecu + "]=" + employe);
} else {
Console.WriteLine("Employe[" + numSecu + "] non trouvé...");
}
numSecu = "xx";
employe = query.SetString("numSecu", numSecu).UniqueResult<Employe>();
if (employe != null) {
Console.WriteLine("Employe[" + numSecu + "]=" + employe);
} else {
Console.WriteLine("Employe[" + numSecu + "] non trouvé...");
}
// işlemi kaydet
transaction.Commit();
}
}
} catch (Exception e) {
Console.WriteLine("L'exception suivante s'est produite : " + e.Message);
}
}
Açıklamalar
- 10. satır: numSecu ile parametreleri ayarlanan ve çalıştırılacak Select sorgusu
- 11. satır: numSecu parametresine bir değer atanması ve tek bir sonuç elde etmek için UniqueResult yönteminin çalıştırılması.
Ekranda görüntülenen sonuç:
Recherche d'un employé -------------------------------------
Employe[254104940426058]=[254104940426058|Jouveinal|Marie|5 rue des oiseaux|St Corentin|49203|[2|2,1|2,1|3,1|15]]
Employe[xx] non trouvé...
6.5.4. Geçersiz varlıkların eklenmesi
Aşağıdaki yöntem, başlatılmamış bir [Employe] öğesini kaydetmeye çalışıyor.
// SaveEmptyEmployee
static void SaveEmptyEmployee() {
try {
// oturum açma
using (ISession session = sessionFactory.OpenSession()) {
// işlem başlangıcı
using (ITransaction transaction = session.BeginTransaction()) {
// boş bir çalışan oluşturuluyor
Employe e = new Employe();
// var olmayan bir tazminat oluşturuluyor
Indemnites i = new Indemnites() { Id = 0, Indice = 3, BaseHeure = 1.93, EntretienJour = 2, RepasJour = 3, IndemnitesCp = 12 };
// bu tazminat çalışana atanır
e.Indemnites = i;
// diğer alanları boş bırakarak çalışanı kaydediyoruz
session.Save(e);
// işlemi onaylayın
transaction.Commit();
}
}
} catch (Exception e) {
Console.WriteLine("L'exception suivante s'est produite : " + e.Message);
}
}
Açıklamalar
[Employe] sınıfının kodunu hatırlayalım:
namespace PamNHibernateDemos {
public class Employe {
// otomatik özellikler
public virtual int Id { get; set; }
public virtual int Version { get; set; }
public virtual string SS { get; set; }
public virtual string Nom { get; set; }
public virtual string Prenom { get; set; }
public virtual string Adresse { get; set; }
public virtual string Ville { get; set; }
public virtual string CodePostal { get; set; }
public virtual Indemnites Indemnites { get; set; }
// oluşturucular
public Employe() {
}
// ToString
public override string ToString() {
return string.Format("[{0}|{1}|{2}|{3}|{4}|{5}|{6}]", SS, Nom, Prenom, Adresse, Ville, CodePostal, Indemnites);
}
}
}
Başlatılmamış bir [Employe] nesnesinin tüm string türündeki alanları null değerine sahip olacaktır. Kayıt, [employes] tablosuna eklenirken, NHibernate bu alanlara karşılık gelen sütunları boş bırakacaktır. Ancak [employes] tablosunda tüm sütunlar not null özniteliğine sahiptir ve bu da değeri olmayan sütunlara izin vermez. Bu durumda ADO.NET sürücüsü bir istisna oluşturacaktır:
6.5.5. Bir işlem içinde aynı endekse sahip iki tazminatın oluşturulması
[indemnites] tablosunda, [indice] sütunu "unique" özniteliği ile tanımlanmıştır; bu da aynı indekse sahip iki satırın bulunmasını engeller. Aşağıdaki yöntem, bir işlem içinde aynı indekse sahip iki tazminat kaydı oluşturur:
// CreateIndemnites1
static void CreateIndemnites1() {
try {
// oturum açma
using (ISession session = sessionFactory.OpenSession()) {
// işlem başlangıcı
using (ITransaction transaction = session.BeginTransaction()) {
// aynı endekse sahip iki tazminat oluşturulur
Indemnites i1 = new Indemnites() { Id = 0, Indice = 1, BaseHeure = 1.93, EntretienJour = 2, RepasJour = 3, IndemnitesCp = 12 };
Indemnites i2 = new Indemnites() { Id = 0, Indice = 1, BaseHeure = 1.93, EntretienJour = 2, RepasJour = 3, IndemnitesCp = 12 };
// bunlar kaydediliyor
session.Save(i1);
session.Save(i2);
// işlemi onaylama
transaction.Commit();
}
}
} catch (Exception e) {
Console.WriteLine("L'exception suivante s'est produite : " + e.Message);
}
}
Açıklamalar
- 9. ve 10. satırlarda, aynı indekse sahip iki Indemnites varlığı oluşturulur. Ancak veritabanında, INDICE sütunu, UNIQUE özniteliğine sahiptir.
- 12. ve 13. satırlarda, iki Indemnites varlığı kalıcılık bağlamına eklenir. Bu bağlam, 15. satırdaki işlemin onaylanması sırasında veritabanıyla senkronize edilir. Bu senkronizasyon, iki adet INSERT oluşmasına neden olacaktır. İkincisi, INDICE sütununun tekilliği nedeniyle bir istisna oluşturacaktır. Bir işlem içinde olduğumuz için, ilk INSERT geri alınacaktır.
Elde edilen sonuç şöyledir:
- satırda, [indemnites] tablosunun boş olduğu görülebilir. Herhangi bir ekleme yapılmamıştır.
6.5.6. İşlem dışında aynı endekse sahip iki tazminatın oluşturulması
Aşağıdaki yöntem, işlem kullanmadan aynı endekse sahip iki tazminat oluşturur:
// CreateIndemnites2
static void CreateIndemnites2() {
try {
// oturum açma
using (ISession session = sessionFactory.OpenSession()) {
// aynı endekse sahip iki tazminat oluşturulur
Indemnites i1 = new Indemnites() { Id = 0, Indice = 1, BaseHeure = 1.93, EntretienJour = 2, RepasJour = 3, IndemnitesCp = 12 };
Indemnites i2 = new Indemnites() { Id = 0, Indice = 1, BaseHeure = 1.94, EntretienJour = 2, RepasJour = 3, IndemnitesCp = 12 };
// bunlar kaydedilir
session.Save(i1);
session.Save(i2);
}
} catch (Exception e) {
Console.WriteLine("L'exception suivante s'est produite : " + e.Message);
}
}
Açıklamalar
- Burada, önceki kodla aynı kod kullanılmaktadır, ancak işlem yapılmamaktadır.
- Kalıcılık bağlamının veritabanıyla senkronizasyonu, bu bağlamın kapatılmasıyla (13. satırda Session'in kapatılması) gerçekleştirilecektir. Senkronizasyon, iki adet INSERT işlemine neden olacaktır. İkincisi, INDICE sütununun tekilliği nedeniyle başarısız olacaktır. Ancak işlem içinde olmadığımız için, ilk INSERT geri alınmayacaktır.
Elde edilen sonuç şöyledir:
Yöntem çalıştırılmadan önce veritabanı boştu. 6. satırda, [indemnites] tablosunda bir satır olduğu görülebilir.


















