Skip to content

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:

  1. C# 2008 Dili: [.NET 3.5 Çerçevesi ile C# Sürüm 3.0'ı Öğrenme (2008)]
  2. [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:

  1. veri kaynağıyla bir bağlantı kurar
  2. veri kaynağıyla okuma/yazma işlemlerini gerçekleştirir
  3. 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
ConnectionString
P
veritabanına bağlantı dizesi. Belirli bir veritabanıyla bağlantı kurulması için gerekli tüm parametreleri belirtir.
Open
M
ConnectionString ile tanımlanan veritabanına bağlantıyı açar
Close
M
bağlantıyı kapatır
BeginTransaction
M
işlemi başlatır.
State
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:

1
2
3
IDbConnection connexion=new Connection();
connexion.ConnectionString=...;
connexion.Open();

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
CommandType
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
CommandText
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ı
Connection
P
SQL emrini yürütmek için kullanılacak IDbConnection bağlantısı
Transaction
P
SQL emrini yürütmek için kullanılacak IDbTransaction işlemi
Parameters
P
parametreleri ayarlanmış bir SQL emrinin parametre listesi. "update articles set price=price*1.1 where id=@id" emrinin @id parametresi vardır.
ExecuteReader
M
SQL ve Select emirlerini yürütmek için. Select'in sonucunu temsil eden bir IDataReader nesnesi elde edilir.
ExecuteNonQuery
M
SQL Güncelleme, Ekleme, Silme komutunu çalıştırmak için. İşlemden etkilenen satır sayısı (güncellenen, eklenen, silinen) elde edilir.
ExecuteScalar
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.
CreateParameter
M
parametreleri ayarlanmış bir SQL emri için IDbParameter parametrelerini oluşturmak için.
Prepare
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:

// bağlantı açma 
IDbConnection connexion=...
connexion.Open();
// komut hazırlığı
IDbCommand commande=new Command();
commande.Connection=connexion;
// select komutunun yürütülmesi
commande.CommandText="select ...";
IDbDataReader reader=commande.ExecuteReader();
...
// update, insert, delete komutlarının yürütülmesi
commande.CommandText="insert ...";
int nbLignesInsérées=commande.ExecuteNonQuery();
...
// bağlantı kapatma
connexion.Close();

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
FieldCount
P
IDataReader tablosundaki sütun sayısı
GetName
M
GetName(i), IDataReader tablosundaki i numaralı sütunun adını döndürür.
Item
P
Item[i], IDataReader tablosunun geçerli satırındaki i numaralı sütunu temsil eder.
Read
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.
Close
M
IDataReader tablosunu kapatır.
GetBoolean
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.
Getvalue
M
Getvalue(i): IDataReader tablosunun geçerli satırındaki i numaralı sütunun değerini object türü olarak döndürür.
IsDBNull
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:

// bağlantı açma 
IDbConnection connexion=...
connexion.Open();
// komut hazırlığı
IDbCommand commande=new Command();
commande.Connection=connexion;
// select komutunun yürütülmesi
commande.CommandText="select ...";
IDataReader reader=commande.ExecuteReader();
// sonuçların işlenmesi
while(reader.Read()){
     // geçerli satırı değerlendirme
        ...
}
// okuyucuyu kapatma
reader.Close();
// bağlantıyı kapatma
connexion.Close();

Ö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:

#
# `cotisations` tablosunun yapısı: 
#

CREATE TABLE `cotisations` (
  `ID` bigint(20) NOT NULL auto_increment,
  `SECU` double NOT NULL,
  `RETRAITE` double NOT NULL,
  `CSGD` double NOT NULL,
  `CSGRDS` double NOT NULL,
  `VERSION` int(11) NOT NULL,
  PRIMARY KEY  (`ID`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=latin1;

#
# `indemnites` tablosunun yapısı: 
#

CREATE TABLE `indemnites` (
  `ID` bigint(20) NOT NULL auto_increment,
  `ENTRETIEN_JOUR` double NOT NULL,
  `REPAS_JOUR` double NOT NULL,
  `INDICE` int(11) NOT NULL,
  `INDEMNITES_CP` double NOT NULL,
  `BASE_HEURE` double NOT NULL,
  `VERSION` int(11) NOT NULL,
  PRIMARY KEY  (`ID`),
  UNIQUE KEY `INDICE` (`INDICE`)
) ENGINE=InnoDB AUTO_INCREMENT=9 DEFAULT CHARSET=latin1;

#
# `employes` tablosunun yapısı: 
#

CREATE TABLE `employes` (
  `ID` bigint(20) NOT NULL auto_increment,
  `PRENOM` varchar(20) NOT NULL,
  `SS` varchar(15) NOT NULL,
  `ADRESSE` varchar(50) NOT NULL,
  `CP` varchar(5) NOT NULL,
  `VILLE` varchar(30) NOT NULL,
  `NOM` varchar(30) NOT NULL,
  `VERSION` int(11) NOT NULL,
  `INDEMNITE_ID` bigint(20) NOT NULL,
  PRIMARY KEY  (`ID`),
  UNIQUE KEY `SS` (`SS`),
  KEY `FK_EMPLOYES_INDEMNITE_ID` (`INDEMNITE_ID`),
  CONSTRAINT `FK_EMPLOYES_INDEMNITE_ID` FOREIGN KEY (`INDEMNITE_ID`) REFERENCES `indemnites` (`ID`)
) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=latin1;

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] &lt;%X{auth}&gt; - %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] &lt;%X{auth}&gt; - %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] &lt;%X{auth}&gt; - %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>
  1. 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:

ID
otomatik artan türünde birincil anahtar
VERSION
kayıt sürüm numarası
SECU
sosyal güvenlik katkı payı oranı (yüzde)
RETRAITE
emeklilik katkı payı oranı
CSGD
indirilebilir genel sosyal katkı payı oranı
CSGRDS
genel sosyal katkı payı ve sosyal borç geri ödemesi katkı payı oranı

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.

  1. 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:

ID
otomatik artan türünde birincil anahtar
VERSION
kayıt sürüm numarası
BASE_HEURE
bir saatlik nöbetin euro cinsinden maliyeti
ENTRETIEN_JOUR
Nöbet tutma başına günlük tazminat (Euro)
REPAS_JOUR
Nöbet tutulan her gün için euro cinsinden yemek ödeneği
INDEMNITES_CP
Ücretli izin ödenekleri. Bu, temel maaşa uygulanacak bir yüzde oranıdır.

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:

ID
otomatik artan türünde birincil anahtar
VERSION
kayıt sürüm numarası
PRENOM
çalışanın adı
NOM
soyadı
ADRESSE
adresi
CP
posta kodu
VILLE
şehri
INDEMNITE_ID
INDEMNITES (ID) üzerinde yabancı anahtar

Ö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>
  1. 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:

ITransaction BeginTransaction()
oturumda bir işlem başlatır
ITransaction tx=session.BeginTransaction();
void Clear()
oturumu boşaltır. Oturumda bulunan nesneler serbest kalır.
session.Clear();
void Close()
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();
IQuery CreateQuery(string queryString)
daha sonra çalıştırılmak üzere bir HQL (Hibernate Query Language) sorgusu oluşturur.
IQuery query=session.createQuery("select e from Employe e);
void Delete(object obj)
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);
void Flush()
oturumun veritabanıyla senkronizasyonunu zorlar. Oturumun içeriği değişmez.
session.Flush();
T Get<T>(object id)
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);
object Save(object obj)
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);
SaveOrUpdate(object obj)
obj'nin birincil anahtarı yoksa Save işlemini, zaten birincil anahtarı varsa Update işlemini gerçekleştirir.
void Update(object obj)
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:

IQuery query=session.createQuery("select e from Employe e);

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:

IList<T> List<T>()
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>();
IList List()
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.
T UniqueResult<T>()
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:

1
2
3
string numSecu;
...
Employe e=session.createQuery("select e from Employe e where e.SS=:num").SetString("num",numSecu).UniqueResult<Employe>();
  1. 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ç:

Affichage base -------------------------------------
--------------- liste des employés
[254104940426058|Jouveinal|Marie|5 rue des oiseaux|St Corentin|49203|[1|1,93|2|3|12]]
[260124402111742|Laverti|Justine|La Brûlerie|St Marcel|49014|[2|2,1|2,1|3,1|15]]

--------------- 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. 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:

sauvegarde d'un employé vide -------------------------------------
L'exception suivante s'est produite : could not insert: [PamNHibernateDemos.Employe][SQL: INSERT INTO EMPLOYES (VERSION, SS, NOM, PRENOM, ADRESSE, VILLE, CP, INDEMNITE_ID) VALUES (?, ?, ?, ?, ?, ?, ?, ?)]

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:

Effacement base -------------------------------------
--------------- çalışanların silinmesi
--------------- tazminatların silinmesi
--------------- katkı payı oranlarının silinmesi
Création de deux indemnités de même indice dans une transaction --------------
L'exception suivante s'est produite : could not insert: [PamNHibernateDemos.Indemnites][SQL: INSERT INTO INDEMNITES (VERSION, INDICE, BASE_HEURE, ENTRETIEN_JOUR, REPAS_JOUR, INDEMNITES_CP) VALUES (?, ?, ?, ?, ?, ?)]
Affichage base -------------------------------------
--------------- çalışan listesi
--------------- tazminat listesi
--------------- katkı payı oranları tablosu
  1. 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:

1
2
3
4
5
6
7
Création de deux indemnités de même indice sans transaction --------------
L'exception suivante s'est produite : could not insert: [PamNHibernateDemos.Indemnites][SQL: INSERT INTO INDEMNITES (VERSION, INDICE, BASE_HEURE, ENTRETIEN_JOUR, REPAS_JOUR, INDEMNITES_CP) VALUES (?, ?, ?, ?, ?, ?)]
Affichage base -------------------------------------
--------------- çalışan listesi
--------------- tazminat listesi
[1|1,93|2|3|12]
--------------- katkı payı oranları tablosu

Yöntem çalıştırılmadan önce veritabanı boştu. 6. satırda, [indemnites] tablosunda bir satır olduğu görülebilir.