1. ORM NHibernate'e Giriş
Bu belgenin PDF dosyası |BURADA| adresinde mevcuttur.
Belgedeki örnekler |BURADA| adresinde mevcuttur.
Bu belge, Java Hibernate çerçevesinin .NET karşılığı olan NHibernate’e dair 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: [.NET 3.5 Çerçevesi ile C# Sürüm 3.0'ı Öğrenme (2008)]
- [Spring IoC], [.NET için Spring IoC (2005)] adresinde 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 zaman zaman okuma önerileri yer almaktadır. Bu öneriler önceki belgelere atıfta bulunmaktadır.
Araçlar
Bu vaka çalışmasında kullanılan araçlar, web üzerinde ücretsiz olarak erişilebilir durumdadır. Bunlar şunlardır (Aralık 2011):
- Nhibernate 3.2, [http://nhforge.org/Default.aspx] adresinde mevcuttur
- Spring.net 1.3.2, [http://www.springframework.net] adresinde mevcuttur. 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üne ait ADO.NET 6.4.4 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ı, bir [libnet4] klasöründe toplanmıştır:
![]() |
1.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. Bu API'in temel yöntemlerini hatırlayalım.
Bağlı modda uygulama:
- veri kaynağıyla bir bağlantı kurar
- veri kaynağıyla okuma/yazma işlemlerini gerçekleştirir
- bağlantıyı kapatır
Bu işlemlerle esas olarak üç ADO.NET arayüzü ilgilidir:
- IDbConnection, bağlantının özelliklerini ve yöntemlerini kapsar.
- IDbCommand, yürütülen SQL komutunun özelliklerini ve yöntemlerini kapsayan bir nesnedir.
- IDataReader, SQL Select komutunun sonucunun özelliklerini ve yöntemlerini kapsar.
IDbConnection arayüzü
Veritabanıyla olan bağlantıyı yönetmek için kullanılır. Bu arayüzün M yöntemleri ve P özellikleri arasında şunlar bulunur:
Ad | Tür | Rol |
P | veritabanına bağlantı dizesi. Belirli bir veritabanıyla bağlantı kurulması için gerekli tüm parametreleri belirtir. | |
M | ConnectionString ile tanımlanan veritabanına bağlantıyı açar | |
M | bağlantıyı kapatır | |
M | işlemi başlatır. | |
P | bağlantı durumu: ConnectionState.Closed, ConnectionState.Open, ConnectionState.Connecting, ConnectionState.Executing, ConnectionState.Fetching, ConnectionState.Broken |
Connection, IDbConnection arayüzünü uygulayan bir sınıf ise, bağlantı şu şekilde açılabilir:
IDbCommand arayüzü
Bir SQL komutunu veya depolanmış bir yordamı yürütmek için kullanılır. Bu arayüzün M yöntemleri ve P özellikleri arasında şunlar bulunur:
Ad | Tür | Rol |
P | yürütülmesi gerekeni belirtir - değerlerini bir sıralamadan alır: - CommandType.Text: CommandText özelliğinde tanımlanan SQL komutunu yürütür. Bu, varsayılan değerdir. - CommandType.StoredProcedure: veritabanında depolanmış bir yordamı yürütür | |
P | - CommandType = CommandType.Text ise yürütülmesi gereken SQL komutunun metni - CommandType = CommandType.StoredProcedure ise çalıştırılacak saklı yordamın adı | |
P | SQL emrini yürütmek için kullanılacak IDbConnection bağlantısı | |
P | SQL emrini yürütmek için kullanılacak IDbTransaction işlemi | |
P | parametreleri ayarlanmış bir SQL emrinin parametre listesi. "update articles set price=price*1.1 where id=@id" emrinin @id parametresi vardır. | |
M | SQL ve Select emirlerini yürütmek için. Select'in sonucunu temsil eden bir IDataReader nesnesi elde edilir. | |
M | SQL Güncelleme, Ekleme, Silme komutunu çalıştırmak için. İşlemden etkilenen satır sayısı (güncellenen, eklenen, silinen) elde edilir. | |
M | SQL komutunu çalıştırmak için; Select komutu, "select count(*) from articles" örneğinde olduğu gibi tek bir sonuç döndürür. | |
M | parametreleri ayarlanmış bir SQL emri için IDbParameter parametrelerini oluşturmak için. | |
M | farklı parametrelerle birden çok kez yürütüldüğünde, parametreli bir sorgunun yürütülmesini optimize etmenizi sağlar. |
Command, IDbCommand arayüzünü uygulayan bir sınıf ise, işlem içermeyen bir SQL emrinin yürütülmesi aşağıdaki gibi olacaktır:
IDataReader arayüzü
, bir SQL Select emrinin sonuçlarını kapsüllemek için kullanılır. Bir IDataReader nesnesi, sırayla işlenen satır ve sütunlardan oluşan bir tabloyu temsil eder: önce 1. satır, sonra 2. satır, ... Bu arayüzün M yöntemleri ve P özellikleri arasında şunlar bulunur:
Ad | Tür | Rol |
P | IDataReader tablosundaki sütun sayısı | |
M | GetName(i), IDataReader tablosundaki i numaralı sütunun adını döndürür. | |
P | Item[i], IDataReader tablosunun geçerli satırındaki i numaralı sütunu temsil eder. | |
M | IDataReader tablosunun bir sonraki satırına geçer. Okuma işlemi başarılı olursa True boole değerini, aksi takdirde False değerini döndürür. | |
M | IDataReader tablosunu kapatır. | |
M | GetBoolean(i): IDataReader tablosunun geçerli satırındaki i numaralı sütunun boole değerini döndürür. Diğer benzer yöntemler şunlardır: GetDateTime, GetDecimal, GetDouble, GetFloat, GetInt16, GetInt32, GetInt64, GetString. | |
M | Getvalue(i): IDataReader tablosunun geçerli satırındaki i numaralı sütunun değerini object türü olarak döndürür. | |
M | IsDBNull(i), IDataReader tablosunun geçerli satırındaki i numaralı sütunda değer yoksa (bu durum SQL NULL değeriyle gösterilir) True değerini döndürür. |
Bir IDataReader nesnesinin işlenmesi genellikle aşağıdaki gibi olur:
Önceki mimaride,
![]() |
[ADO.NET] konektörü, SGBD ile ilişkilidir. Dolayısıyla, [IDbConnection] arayüzünü uygulayan sınıf şudur:
- SGBD için [MySQLConnection] sınıfı, MySQL
- 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çevesini 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.
1.2. Örnek veritabanı
NHibernate ile nasıl çalışılacağını göstermek için aşağıdaki MySQL [dbpam_nhibernate] veritabanını kullanacağız:
![]() |
- [1]'te, veritabanında üç tablo bulunmaktadır:
- [employes]: Bir kreşin çalışanlarını kaydeden bir tablo
- [cotisations]: sosyal güvenlik prim oranlarını kaydeden bir tablo
- [indemnites]: Çalışanların maaş hesaplamasına yönelik bilgileri kaydeden bir tablo
[employes] tablosu
![]() |
- [2], çalışan tablosu; [3] ise bu tablonun alanlarının açıklamalarıdır
Tablonun içeriği şu şekilde olabilir:
[cotisations] tablosu
![]() |
- [4]'te prim tablosu ve [5]'te bu tablonun alanlarının açıklamaları
Tablonun içeriği şu şekilde olabilir:
[indemnites] tablosu
![]() |
- [6]'te tazminat tablosu ve [7]'te bu tablonun alanlarının açıklamaları yer almaktadır
Tablonun içeriği şu şekilde olabilir:
Veritabanı yapısının 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.
1.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çevesinin DLL dosyası
- [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ı
1.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ğlantı 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ı örneği verilmiştir:
<?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ı, log4net.Config.XmlConfigurator.Configure(); komutuyla program üzerinden 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 NHibernate yapılandırma bölümünü tanımlar. İki özniteliği vardır: name ve type.
- [name] özniteliği, yapılandırma bölümüne ad verir. Bu bölüm, burada 11-24. satırlardaki <name>...</name> etiketleriyle sınırlandırılmalıdır; bu durumda <hibernate-configuration>...</hibernate-configuration> etiketleri kullanılı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 sınıfını 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ı arasında yer almaktadı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ının 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 [NHibernate] geliştirilmiştir. Burada tanımlanmış olan çeşitli ad alanları (namespace) bulunur.
- [4]'te, kullanılabilir çeşitli lehçeleri tanımlayan sınıfların bulunduğu [NHibernate.Dialect] ad alanı yer alı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ı:
<!-- 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.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 SQL Select komutunu ç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, projenin özellikleri
- [Application] sekmesinde [2], oluşturulacak [3] assembly'sinin adı.
- Çı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] ve [6] dosyalarında bulunması gerektiği anlaşılmaktadır.
1.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 |
1.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; }
// yapıcılar
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ı bu sınıfı miras alacak ve özelliklerini yeniden tanımlayacak (override) olduğundan, 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ı alacak 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 değerinin 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 kaydetmesi gerektiğ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 almalıdır. Ç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. 1.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ğeri MySQL'in oluşturması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 belirtir.
1.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.
1.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] nesnesinde gerçekleştirilen bir ekleme (save) veya güncelleme (update) işlemi, bu nesnenin içerdiği [Indemnites] nesnesine de yansıtılmalıdır.
- delete: [Employe] nesnesinin silinmesi, içindeki [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ındaki NHibernate yapılandırmasını hatırlatalı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] olarak, 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.
1.4. API'ten NHibernate'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.
1.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ı.
1.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ılacaktı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, bloğu içinde işlem, bir Commit komutuyla onaylanır (10. satır). İşlem sırasında bir kalıcılık işlemi bir istisna oluşturursa, işlem using'ten çıkıldığında bir Rollback komutuyla otomatik olarak 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 tetiklenebilecek olası bir istisnayı yakalamaya olanak tanır.
1.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 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 işleminden önce bir birincil anahtara sahip değildir. Save'ten sonra birincil anahtarı olur. Oturum senkronizasyonu sırasında, veritabanında 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 işlemiyle bir çalışanı yükleriz Çalışan e = session.Get<Çalışan>(143); // adını değiştiriyoruz e.Nom = ...; // veritabanında güncellenir session.Update(e); |
1.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>(); | |
sorgunun sonucunu, listenin her bir elemanının Select sorgusunun bir satır sonucunu nesne dizisi 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(dize adı, tek değer)
- - SetDouble(dize ad, çift değer)
- - SetInt32(dize ad, int32 değer)
- ..
1.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, günlükleri oluşturmaya yarayan bir araç
- [2]'te, veritabanı tablolarının görüntü sınıfları
- [3], 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.
1.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.
1.5.2. Veritabanına veri ekleme
[FillDataBase.cs] programı, veritabanına veri 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
}
// 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 listesini alıyoruz
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ında kalıcı hale getirilir
- 112. satır: Cotisations varlığı da veritabanına kaydedilir
- 102. ve 103. satırlardaki Indemnités varlıklarının kalıcı hale getirilmemiş olması şaşırtıcı gelebilir. Aslında bunlar, Employe varlıklarıyla aynı anda kalıcı hale getirilmiş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 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]
1.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 aranıyor 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é...
1.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ıyor
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] nesnesi, tüm string türündeki alanlarında 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:
1.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ütununda UNIQUE özniteliği bulunmaktadır.
- 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.
1.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ılıyor, ancak işlem yok.
- Kalıcılık bağlamının veritabanıyla senkronizasyonu, bu bağlamın kapatılmasıyla gerçekleştirilecektir (13. satır, Session'in kapatılması). 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.























