7. [SimuPaie] uygulaması – sürüm 3 – NHibernate ile 3 katmanlı mimari
Önerilen okumalar: "C# 2008 Dili, Bölüm 4: 3 Katmanlı Mimariler, NUnit testleri, Spring çerçeve".
7.1. Uygulamanın genel mimarisi
[SimuPaie] uygulaması artık aşağıdaki üç katmanlı yapıya sahip olacaktır:
![]() |
- [1-dao] katmanı (dao=Veri Erişim Nesnesi) veri erişiminden sorumlu olacaktır.
- [2-métier] katmanı, uygulamanın iş mantığı olan maaş hesaplamasından sorumlu olacaktır.
- [3-ui] katmanı (ui=Kullanıcı Arayüzü), verilerin kullanıcıya sunulmasından ve kullanıcının isteklerinin yerine getirilmesinden sorumlu olacaktır. Bu işlevi sağlayan modüllerin tamamına [Application] adını veriyoruz. Bu katman, kullanıcıyla etkileşim kuran unsurdur.
- Üç katman, .NET arayüzlerinin kullanılmasıyla birbirinden bağımsız hale getirilecektir.
- Farklı katmanların entegrasyonu Spring IoC ile gerçekleştirilecektir
Bir müşteri talebinin işlenmesi aşağıdaki adımlara göre gerçekleşir:
- Müşteri, uygulamaya bir talep gönderir.
- Uygulama bu talebi işler. Bunu yapmak için, [métier] katmanının yardımına ihtiyaç duyabilir; veritabanıyla veri alışverişi yapılması gerekiyorsa, bu katman da [dao] katmanına ihtiyaç duyabilir.
- Uygulama, [métier] katmanından bir yanıt alır. Bu yanıta göre, müşteriye uygun görünümü (= yanıtı) gönderir.
Bir çocuk bakıcısının maaş hesaplamasını örnek olarak ele alalım. Bu işlem birkaç aşamayı gerektirecektir:
![]() |
- [ui] katmanı, kullanıcıdan
- maaş hesaplaması yapılacak kişinin kimliğini
- bu kişinin çalıştığı gün sayısını
- çalışılan saat sayısını
- Bunun için, kullanıcının bunlardan birini seçebilmesi amacıyla [EMPLOYES] tablosunda bulunan kişilerin listesini (soyadı, adı, SS) kullanıcıya sunması gerekecektir. [ui] katmanı, bu bilgileri almak için [2, 3, 4, 5, 6, 7] yolunu kullanacaktır. [2] işlemi, çalışan listesinin talep edilmesidir; [7] işlemi ise bu talebe verilen yanıttır. Bu işlem tamamlandıktan sonra, [ui] katmanı, [8] aracılığıyla çalışan listesini kullanıcıya sunabilir.
- Kullanıcı, çalışılan gün sayısını ve çalışılan saat sayısını [ui] katmanına iletecektir. Bu, yukarıdaki [1] işlemidir. Bu aşamada kullanıcı yalnızca [ui] katmanıyla etkileşime girer. Girilen verilerin geçerliliğini kontrol eden de bu katmandır. Bu işlem tamamlandıktan sonra kullanıcı maaş hesaplamasını talep eder.
- [ui] katmanı, bu hesaplamayı yapması için iş katmanına talepte bulunur. Bunun için kullanıcıdan aldığı verileri iş katmanına iletir. Bu, [2] işlemidir.
- [metier] katmanı, görevini başarıyla yerine getirebilmek için bazı bilgilere ihtiyaç duyar:
- kişi hakkında daha kapsamlı bilgiler (adres, endeks, ...)
- endeksine bağlı ödenekler
- brüt maaştan kesilecek çeşitli sosyal güvenlik prim oranları
Bu bilgileri, [3, 4, 5, 6] yolunu kullanarak [dao] katmanından isteyecektir. [3] ilk istektir ve [6] bu isteğe verilen yanıttır.
- İhtiyacı olan tüm verilere sahip olan [metier] katmanı, kullanıcı tarafından seçilen kişinin maaşını hesaplar.
- [metier] katmanı artık (d) adımında [ui] katmanı tarafından yapılan talebe yanıt verebilir. Bu, [7] yoludur.
- [ui] katmanı, bu sonuçları uygun bir biçimde biçimlendirerek kullanıcıya sunacaktır. Bu işlem, [8] yolunda gerçekleştirilir.
- Bu sonuçların bir dosyaya veya veritabanına kaydedilmesi gerektiğini düşünebiliriz. Bu işlem otomatik olarak gerçekleştirilebilir. Bu durumda, (f) işleminden sonra [metier] katmanı, [dao] katmanından sonuçları kaydetmesini isteyecektir. Bu işlem için [3, 4, 5, 6] yolu kullanılacaktır. Bu işlem, kullanıcının talebi üzerine de gerçekleştirilebilir. Bu durumda, istek-yanıt döngüsü tarafından [1-8] yolu kullanılacaktır.
Bu açıklamadan, bir katmanın her zaman sağındaki katmanın kaynaklarını kullandığı, asla solundaki katmanın kaynaklarını kullanmadığı anlaşılmaktadır.
Bu 3 katmanlı mimarinin ilk uygulamamız,
- [dao] ve [metier] katmanları, DLL tarafından uygulanacak
- [ui] katmanı ise sürüm 1'in web formu ile uygulanacaktır (bkz. paragraf 4.2.1).
Öncelikle [dao] katmanını NHibernate çerçeve yapısı ile hayata geçiriyoruz.
7.2. Veriye erişim katmanı [dao]
![]() |
7.2.1. [dao] katmanının Visual Studio C# projesi
[dao] katmanının Visual Studio projesi şöyledir:
![]() |
- [1]'te, projenin tamamı
- [2]'te, projenin farklı sınıfları
- [3]'te, projenin referansları.
- [4] dosyasında, takip edecek çeşitli projeler için gerekli olan DLL dosyalarının bir araya getirildiği bir [lib] klasörü bulunmaktadır
Projenin [3] referanslarında şu DLL'ler bulunur:
- NHibernate: ORM ve NHibernate için
- MySql.Data: SGBD ve MySQL için ADO.NET sürücüsü
- Spring.Core: Spring çerçeve için
- log4net: bir günlük kütüphanesi
- nunit.framework: birim test kütüphanesi
Bu referanslar [lib] [4] klasöründen alınmıştır. Tüm bu referansların "Yerel Kopya" özelliğinin "True" olarak ayarlandığından emin olunmalıdır. [5]:
![]() |
7.2.2. [dao] katmanındaki varlıklar
![]() |
[dao] katmanı için gerekli varlıklar (nesneler), projenin [entites] klasöründe toplanmıştır. Bunlardan bazıları bize zaten biliniyor: 6.3.2.1. paragrafında açıklanan [Cotisations], 6.3.2.3. paragrafında açıklanan [Employe], 6.3.2.2. paragrafında açıklanan [Indemnites]. Hepsi [Pam.Dao.Entites] ad alanında yer almaktadır.
[Employe] sınıfı şu şekilde gelişmektedir:
namespace Pam.Dao.Entites {
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; }
// yapıcılar
public Employe() {
}
// ToString
public override string ToString() {
return string.Format("[{0},{1},{2},{3},{4},{5},{6}]", SS, Nom, Prenom, Adresse, Ville, CodePostal, Indemnites);
}
}
}
7.2.3. [PamException] sınıfı
[dao] katmanı, harici bir kaynakla veri alışverişi yapmakla görevlidir. Bu veri alışverişi başarısız olabilir. Örneğin, bilgiler İnternet üzerindeki uzak bir hizmetten talep edilirse, herhangi bir ağ arızası durumunda bu bilgilerin alınması başarısız olacaktır. Bu tür hatalarda, Java'da bir istisna atmak yaygın bir uygulamadır. İstisna, [RunTimeException] türü veya bunun türevlerinden biri değilse, yöntemin imzasında bu yöntemin bir istisna attığı (throws) belirtilmelidir. .NET'te tüm istisnalar kontrolsüzdür, c.a.d. Bu durumda, [GetAllIdentitesEmployes, GetEmploye, GetCotisations] yöntemlerinin bir istisna atabileceğini belirtmeye gerek yoktur.
Ancak, istisnaların işlenişi farklı olabileceğinden, istisnaları birbirinden ayırt edebilmek önemlidir. Böylece, çeşitli istisna türlerini yöneten kod şu şekilde yazılabilir:
try{
... code pouvant générer divers types d'exceptions
}catch (Exception1 ex1){
...on gère un type d'exceptions
}catch (Exception2 ex2){
...on gère un autre type d'exceptions
}finally{
...
}
Bu nedenle, uygulamamızın [dao] katmanı için bir istisna türü oluşturuyoruz. Bu, aşağıdaki [PamException] türüdür:
using System;
namespace Pam.Dao.Entites {
public class PamException : Exception {
// hata kodu
public int Code { get; set; }
// yapıcılar
public PamException() {
}
public PamException(int Code)
: base() {
this.Code = Code;
}
public PamException(string message, int Code)
: base(message) {
this.Code = Code;
}
public PamException(string message, Exception ex, int Code)
: base(message, ex) {
this.Code = Code;
}
}
}
- 2. satır: Sınıf, [Pam.Dao.Entites] ad alanına aittir
- 4. satır: Sınıf, [Exception] sınıfından türetilmiştir
- 7. satır: Bir hata kodu olan [Code] adlı bir public özelliğe sahiptir
- [dao] katmanımızda iki tür oluşturucu kullanacağız:
- 18-21. satırlardaki, aşağıda gösterildiği gibi kullanılabilen oluşturucu:
- (devamı)
- veya 23-26. satırlarda yer alan, daha önce meydana gelmiş bir istisnayı [PamException] türünde bir istisna içine kapsülleyerek yukarıya aktarmaya yarayan oluşturucu:
try{
....
}catch (IOException ex){
// istisna kapsüllenir
throw new PamException("Problème d'accès aux données",ex,10);
}
Bu ikinci yöntemin avantajı, ilk istisnada yer alabilecek bilgilerin kaybolmamasıdır.
7.2.4. NHibernate'in eşleme tabloları <--> sınıfları dosyaları
Uygulamanın mimarisine geri dönelim:
![]() |
Okuma işleminde, NHibernate çerçeve yapısı veritabanındaki verileri kullanır ve bunları az önce sınıflarını tanıttığımız nesnelere dönüştürür. Yazma işleminde ise tam tersini yapar: nesnelerden yola çıkarak veritabanı tablolarındaki satırları oluşturur, günceller ve siler. Tablolar <--> sınıflar dönüşümünü sağlayan dosyalar daha önce tanıtılmıştı:
![]() |
- 6.3.2.1 numaralı paragrafta tanıtılan [Cotisations.hbm.xml] dosyası, [COTISATIONS] tablosu ile [Cotisations] sınıfı arasında eşleştirme yapar
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
namespace="Pam.Dao.Entites" assembly="pam-dao-nhibernate">
<class name="Cotisations" table="COTISATIONS">
<id name="Id" column="ID">
<generator class="native" />
</id>
<version name="Version" column="VERSION"/>
<property name="CsgRds" column="CSGRDS" not-null="true"/>
<property name="Csgd" column="CSGD" not-null="true"/>
<property name="Retraite" column="RETRAITE" not-null="true"/>
<property name="Secu" column="SECU" not-null="true"/>
</class>
</hibernate-mapping>
- 6.3.2.3. paragrafta sunulan [Employe.hbm.xml] dosyası, [EMPLOYES] tablosu ile [Employe] sınıfı arasında eşleştirme yapar
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
namespace="Pam.Dao.Entites" assembly="pam-dao-nhibernate">
<class name="Employe" table="EMPLOYES">
<id name="Id" column="ID">
<generator class="native" />
</id>
<version name="Version" column="VERSION"/>
<property name="SS" column="SS" length="15" not-null="true" unique="true"/>
<property name="Nom" column="NOM" length="30" not-null="true"/>
<property name="Prenom" column="PRENOM" length="20" not-null="true"/>
<property name="Adresse" column="ADRESSE" length="50" not-null="true" />
<property name="Ville" column="VILLE" length="30" not-null="true"/>
<property name="CodePostal" column="CP" length="5" not-null="true"/>
<many-to-one name="Indemnites" column="INDEMNITE_ID" cascade="save-update" lazy="false"/>
</class>
</hibernate-mapping>
- 6.3.2.2. paragrafta sunulan [Indemnites.hbm.xml] dosyası, [INDEMNITES] tablosu ile [Indemnites] sınıfı arasında eşleştirme yapar
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
namespace="Pam.Dao.Entites" assembly="pam-dao-nhibernate">
<class name="Indemnites" table="INDEMNITES">
<id name="Id" column="ID">
<generator class="native" />
</id>
<version name="Version" column="VERSION"/>
<property name="Indice" column="INDICE" not-null="true" unique="true"/>
<property name="BaseHeure" column="BASE_HEURE" not-null="true"/>
<property name="EntretienJour" column="ENTRETIEN_JOUR" not-null="true"/>
<property name="RepasJour" column="REPAS_JOUR" not-null="true" />
<property name="IndemnitesCp" column="INDEMNITES_CP" not-null="true"/>
</class>
</hibernate-mapping>
Bu dosyaların <hibernate-mapping> etiketinde (2. satır) aşağıdaki özniteliklerin bulunduğuna dikkat edilmelidir:
- namespace : Pam.Dao.Entites. [Cotisations], [Employe] ve [Indemnites] sınıfları bu ad alanında bulunmalıdır.
- assembly: pam-dao-nhibernate. [*.hbm.xml] eşleme dosyaları, [pam-dao-nhibernate] adlı bir DLL dosyası içinde yer almalıdır. Bu sonucu elde etmek için C# projesi şu şekilde yapılandırılır:
![]() |
- [1] dosyasına dönüştürülür; projenin derlemesinin adı [pam-dao-nhibernate]'tir
- [2]'te, [*.hbm.xml] eşleme dosyaları [3] proje derlemesine eklenmiştir
7.2.5. [IPamDao] arayüzü, [dao] katmanının adresindedir
Uygulamamızın mimarisine geri dönelim:
![]() |
Basit durumlarda, uygulamanın arayüzlerini keşfetmek için [metier] katmanından başlayabiliriz. Çalışabilmesi için verilere ihtiyaç duyar:
- Bu veriler, dosyalarda, veritabanlarında veya ağ üzerinden zaten mevcut olabilir. Bu veriler, [dao] katmanı tarafından sağlanır.
- henüz mevcut olmayan veriler. Bu durumda veriler, uygulama kullanıcısından elde eden [ui] katmanı tarafından sağlanır.
[dao] katmanı, [metier] katmanına hangi arayüzü sunmalıdır? Bu iki katman arasında hangi etkileşimler mümkündür? [dao] katmanı, [metier] katmanına aşağıdaki verileri sağlamalıdır:
- kullanıcının belirli bir bakıcıyı seçebilmesi için bakıcıların listesi
- seçilen kişi hakkında eksiksiz bilgiler (adres, endeks, ...)
- kişinin endeksine bağlı ödenekler
- farklı sosyal güvenlik prim oranları
Bu bilgiler, maaş hesaplamasından önce bilinmektedir ve bu nedenle depolanabilir. [metier] -> [dao] yönünde, [metier] katmanı, [dao] katmanından maaş hesaplamasının sonucunu kaydetmesini isteyebilir. Burada bunu yapmayacağız.
Bu bilgilerle, [dao] katmanının arayüzünün ilk tanımını yapmaya çalışabiliriz:
using Pam.Dao.Entites;
namespace Pam.Dao.Service {
public interface IPamDao {
// tüm çalışan kimliklerinin listesi
Employe[] GetAllIdentitesEmployes();
// belirli bir çalışan ve primleri
Employe GetEmploye(string ss);
// tüm primlerin listesi
Cotisations GetCotisations();
}
}
- 1. satır: [dao] katmanındaki varlıkların ad alanı içe aktarılır.
- 3. satır: [dao] katmanı, [Pam.Dao.Service] ad alanında yer alır. [Pam.Dao.Entites] ad alanındaki öğeler birden fazla kopya halinde oluşturulabilir. [Pam.Dao.Service] ad alanındaki öğeler ise tek bir kopya (singleton) olarak oluşturulur. Ad alanlarının isimlerinin bu şekilde seçilmesinin nedeni budur.
- 4. satır: Arayüzün adı [IPamDao]'tir. Bu arayüz üç yöntem tanımlar:
- 6. satır: [GetAllIdentitesEmployes], [Employe] türünde bir nesne dizisi döndürür; bu dizi, çocuk bakıcılarının listesini basitleştirilmiş bir biçimde (soyadı, adı, SS) temsil eder.
- 8. satırda, [GetEmploye], [Employe] nesnesini döndürür: yönteme parametre olarak geçirilen sosyal güvenlik numarasına sahip çalışan ve endeksine bağlı ödenekler.
- 10. satırda, [GetCotisations], brüt maaştan kesilecek çeşitli sosyal güvenlik prim oranlarını içeren [Cotisations] nesnesini döndürür.
7.3. [dao] katmanının uygulanması ve testleri
7.3.1. Visual Studio projesi
Visual Studio projesi daha önce tanıtılmıştı. Hatırlayalım:
![]() |
- [1] dosyasında, projenin tamamı
- [2]'te, projenin çeşitli sınıfları. [entites] klasörü, [dao] katmanı tarafından işlenen varlıkları ve NHibernate eşleme dosyalarını içerir. [service] klasörü, [IPamDao] arayüzünü ve bunun [PamDaoNHibernate] uygulamasını içerir. [tests] klasörü, bir konsol testi olan [Main.cs] ve bir birim testi olan [NUnit.cs]'i içerir.
- [3] dosyasında ise proje referansları yer almaktadır.
7.3.2. [Main.cs] konsol test programı
[Main.cs] test programı aşağıdaki mimaride çalıştırılır:
![]() |
Bu program, [IPamDao] arayüzünün yöntemlerini test etmekle görevlidir. Basit bir örnek şu şekilde olabilir:
using System;
using Pam.Dao.Entites;
using Pam.Dao.Service;
using Spring.Context.Support;
namespace Pam.Dao.Tests {
public class MainPamDaoTests {
public static void Main() {
try {
// [dao] katmanının örneklenmesi
IPamDao pamDao = (IPamDao)ContextRegistry.GetContext().GetObject("pamdao");
// çalışan kimliklerinin listesi
foreach (Employe Employe in pamDao.GetAllIdentitesEmployes()) {
Console.WriteLine(Employe.ToString());
}
// bir çalışan ve ödenekleri
Console.WriteLine("------------------------------------");
Console.WriteLine(pamDao.GetEmploye("254104940426058"));
Console.WriteLine("------------------------------------");
// primlerin listesi
Cotisations cotisations = pamDao.GetCotisations();
Console.WriteLine(cotisations.ToString());
} catch (Exception ex) {
// istisna görüntüsü
Console.WriteLine(ex.ToString());
}
//ara
Console.ReadLine();
}
}
}
- 11. satır: Spring'den [dao] katmanına ilişkin bir referans istenir.
- 13-15. satırlar: [IPamDao] arayüzünün [GetAllIdentitesEmployes] yönteminin test edilmesi
- 18. satır: [IPamDao] arayüzünün [GetEmploye] yönteminin test edilmesi
- 21. satır: [IPamDao] arayüzünün [GetCotisations] yönteminin testi
Spring, NHibernate ve log4net, aşağıdaki [App.config] dosyası ile yapılandırılmıştır:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<!-- yapılandırma bölümleri -->
<configSections>
<section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler,log4net" />
<sectionGroup name="spring">
<section name="objects" type="Spring.Context.Support.DefaultSectionHandler, Spring.Core" />
<section name="context" type="Spring.Context.Support.ContextHandler, Spring.Core" />
</sectionGroup>
<section name="hibernate-configuration" type="NHibernate.Cfg.ConfigurationSectionHandler, NHibernate" />
</configSections>
<!-- Spring yapılandırması -->
<spring>
<context>
<resource uri="config://spring/objects" />
</context>
<objects xmlns="http://www.springframework.net">
<object id="pamdao" type="Pam.Dao.Service.PamDaoNHibernate, pam-dao-nhibernate" init-method="init" destroy-method="destroy"/>
</objects>
</spring>
<!-- 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-dao-nhibernate"/>
</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. Program aracılığıyla etkinleştirilmeleri gerekir
avec l'instruction log4net.Config.XmlConfigurator.Configure();
! -->
<log4net>
...
</log4net>
</configuration>
NHibernate dosyasının yapılandırması (10. satır, 25-36. satırlar) 6.3.1. paragrafında açıklanmıştır. 34. satırda, eşleme dosyalarının [pam-dao-nhibernate] derlemesinde bulunduğu belirtilmiştir. Bu, projenin derlemesidir.
Spring yapılandırması 6-9. ve 15-22. satırlarda yapılmıştır. 20. satır, [Main.cs] konsol programı tarafından kullanılan [pamdao] nesnesini tanımlar. <object> etiketinin burada aşağıdaki öznitelikleri vardır:
- type: örneklenecek sınıfı belirler. [IPamDao] arayüzünü uygulayan sınıf, [PamDaoNHibernate] sınıfıdır. Bu sınıf, projenin DLL [pam-dao-nhibernate] dosyasında bulunur.
- init-method: Sınıfın örneklendirilmesinden sonra [PamDaoNHibernate] sınıfının yürütülmesi gereken yöntemi belirtir
- destroy-method: Projenin yürütülmesi tamamlandığında Spring konteyneri yok edildiğinde [PamDaoNHibernate] sınıfının yürütülmesi gereken yöntemi.
6.2. paragrafta açıklanan veritabanı kullanılarak yapılan çalıştırma, konsolda aşağıdaki sonucu verir:
- 1-2. satırlar: [Employe] türündeki 2 çalışan; yalnızca [SS, Nom, Prenom] bilgileri ile
- 4. satır: [Employe] türündeki ve [254104940426058] sosyal güvenlik numarasına sahip çalışan
- 5. satır: prim oranları
7.3.3. [PamDaoNHibernate] sınıfına ait kayıt
![]() |
[dao] katmanı tarafından uygulanan [IPamDao] arayüzü şöyledir:
using Pam.Dao.Entites;
namespace Pam.Dao.Service {
public interface IPamDao {
// tüm çalışan kimliklerinin listesi
Employe[] GetAllIdentitesEmployes();
// belirli bir çalışanın ek ödemeleriyle birlikte bilgileri
Employe GetEmploye(string ss);
// tüm primlerin listesi
Cotisations GetCotisations();
}
}
Soru: Yukarıdaki [IPamDao] arayüzünü, daha önce sunulduğu şekilde yapılandırılmış NHibernate çerçeve yapısı kullanılarak uygulayan [PamDaoNHibernate] sınıfının kodunu yazınız. Ayrıca Spring tarafından yürütülen init ve destroy yöntemlerini de uygulayacağız. init yöntemi, SessionFactory nesnesini oluşturacak ve bu nesneden Session nesnelerini alacağız. destroy yöntemi ise bu SessionFactory nesnesini kapatacaktır. 6.5. paragrafındaki örneklerden yararlanacağız.
Kısıtlamalar:
[dao] katmanından istenen bazı verilerin tamamen bellekte sığabileceği varsayılacaktır. Bu nedenle, performansı artırmak amacıyla [PamDaoNHibernate] sınıfı şunları bellekte saklayacaktır:
- [EMPLOYES] tablosunu (SS, NOM, PRENOM) şeklinde; [GetAllIdentitesEmployes] yöntemi tarafından gerekli kılınan [Employe] türündeki nesnelerden oluşan bir dizi şeklinde;
- [COTISATIONS] tablosu, [Cotisations] türünde tek bir nesne şeklinde
Bu işlem, sınıfın [init] yönteminde gerçekleştirilecektir. [PamDaoNHibernate] sınıfının iskeleti şu şekilde olabilir:
using System;
...
namespace Pam.Dao.Service {
class PamDaoNHibernate : IPamDao {
// özel alanlar
private Cotisations cotisations;
private Employe[] employes;
private ISessionFactory sessionFactory = null;
// başlatma
public void init() {
try {
// fabrika başlatma
sessionFactory = new Configuration().Configure().BuildSessionFactory();
// prim oranlarını ve çalışanları alıp önbelleğe alıyoruz
.......................
}
// kapatma SessionFactory
public void destroy() {
if (sessionFactory != null) {
sessionFactory.Close();
}
}
// tüm çalışan kimliklerinin listesi
public Employe[] GetAllIdentitesEmployes() {
return employes;
}
// bir özel çalışan ve ödenekleri
public Employe GetEmploye(string ss) {
................................
}
// prim listesi
public Cotisations GetCotisations() {
return cotisations;
}
}
}
7.3.4. NUnit ile birim testleri
Önerilen okumalar: "C# 2008 Dili, Bölüm 4: 3 Katmanlı Mimariler, NUnit testleri, Spring çerçeve".
Önceki test görseldi: Ekrandan beklenen sonuçların elde edildiğini kontrol ediyorduk. Bu, profesyonel ortamda yetersiz bir yöntemdir. Testler her zaman mümkün olduğunca otomatikleştirilmeli ve hiçbir insan müdahalesine gerek kalmayacak şekilde tasarlanmalıdır. İnsanlar yorgunluğa maruz kalır ve testleri doğrulama yetenekleri gün içinde azalır. [NUnit] aracı bu otomasyonu gerçekleştirmeye yardımcı olur. Bu araç, URL [http://www.nunit.org/] adresinde mevcuttur.
[dao] katmanının Visual Studio projesi şu şekilde gelişecektir:
![]() |
- [1]'e, test programı [NUnit.cs]
- [2,3]'e, proje DLL adlı bir dosya oluşturacak ve bu dosya [pam-dao-nhibernate.dll] olarak adlandırılacak
- [4]'e, DLL'e yapılan referans, NUnit: [nunit.framework.dll]
- [5]'e dönüştürüldüğünde, [Main.cs] sınıfı DLL'e dahil edilmeyecektir [pam-dao-nhibernate]
- [6]'e dönüştürüldüğünde, [NUnit.cs] sınıfı DLL ve [pam-dao-nhibernate] sınıflarına dahil edilecektir
'ten NUnit sınıfı şu şekildedir:
using System.Collections;
using NUnit.Framework;
using Pam.Dao.Service;
using Pam.Dao.Entites;
using Spring.Objects.Factory.Xml;
using Spring.Core.IO;
using Spring.Context.Support;
namespace Pam.Dao.Tests {
[TestFixture]
public class NunitPamDao : AssertionHelper {
// test edilecek [dao] katmanı
private IPamDao pamDao = null;
// üretici
public NunitPamDao() {
// [dao] katmanının örneği
pamDao = (IPamDao)ContextRegistry.GetContext().GetObject("pamdao");
}
// başlatma
[SetUp]
public void Init() {
}
[Test]
public void GetAllIdentitesEmployes() {
// çalışan sayısı kontrolü
Expect(2, EqualTo(pamDao.GetAllIdentitesEmployes().Length));
}
[Test]
public void GetCotisations() {
// prim oranının kontrolü
Cotisations cotisations = pamDao.GetCotisations();
Expect(3.49, EqualTo(cotisations.CsgRds).Within(1E-06));
Expect(6.15, EqualTo(cotisations.Csgd).Within(1E-06));
Expect(9.39, EqualTo(cotisations.Secu).Within(1E-06));
Expect(7.88, EqualTo(cotisations.Retraite).Within(1E-06));
}
[Test]
public void GetEmployeIdemnites() {
// bireylerin doğrulanması
Employe employe1 = pamDao.GetEmploye("254104940426058");
Employe employe2 = pamDao.GetEmploye("260124402111742");
Expect("Jouveinal", EqualTo(employe1.Nom));
Expect(2.1, EqualTo(employe1.Indemnites.BaseHeure).Within(1E-06));
Expect("Laverti", EqualTo(employe2.Nom));
Expect(1.93, EqualTo(employe2.Indemnites.BaseHeure).Within(1E-06));
}
[Test]
public void GetEmployeIdemnites2() {
// mevcut olmayan kişi kontrolü
bool erreur = false;
try {
Employe employe1 = pamDao.GetEmploye("xx");
} catch {
erreur = true;
}
Expect(erreur, True);
}
}
}
- 11. satır: Sınıf, onu bir test sınıfı yapan [TestFixture] özniteliğine sahiptir.
- 12. satır: Sınıf, NUnit çerçevesinin (2.4.6 sürümünden itibaren) AssertionHelper yardımcı sınıfından türetilmiştir.
- 14. satır: Özel alan [pamDao], katman erişim arayüzü [dao]'in bir örneğidir. Bu alanın türünün bir sınıf değil, bir arayüz olduğu unutulmamalıdır. Bu, [pamDao] örneğinin yalnızca [IPamDao] arayüzüne ait yöntemlere erişim sağladığı anlamına gelir.
- Sınıfta test edilen yöntemler, [Test] özniteliğine sahip olanlardır. Tüm bu yöntemler için test süreci şu şekildedir:
- öncelikle [SetUp] özniteliğine sahip yöntem çalıştırılır. Bu yöntem, test için gerekli kaynakları (ağ bağlantıları, veritabanı bağlantıları vb.) hazırlamak için kullanılır.
- Ardından test edilecek yöntem çalıştırılır
- ve son olarak [TearDown] özniteliğine sahip yöntem çalıştırılır. Bu yöntem genellikle [SetUp] özniteliğine sahip yöntem tarafından kullanılan kaynakları serbest bırakmak için kullanılır.
- Testimizde, her testten önce tahsis edilecek ve sonrasında serbest bırakılacak kaynaklar bulunmamaktadır. Dolayısıyla, [SetUp] ve [TearDown] özniteliklerine sahip yöntemlere ihtiyacımız yoktur. Örnek olarak, 23-26. satırlarda [SetUp] özniteliğine sahip bir yöntem gösterdik.
- 17-20. satırlar: Sınıf oluşturucu, Spring ve [App.config] yardımıyla özel alan [pamDao]'i başlatır.
- 29-32. satırlar: [GetAllIdentitesEmployes] yöntemini test eder
- 35-42. satırlar: [GetCotisations] yöntemini test eder
- 45-53. satırlar: [GetEmploye] yöntemini test eder
- 56-65. satırlar: bir istisna durumunda [GetEmploye] yöntemini test eder.
Projenin derlenmesi, [bin/Release] klasöründe DLL ve [pam-dao-nhibernate.dll] dosyalarını oluşturur.
![]() |
[bin/Release] klasörü ayrıca şunları içerir:
- proje referanslarının bir parçası olan ve [Copie locale] özniteliği "true" olarak ayarlanmış DLL dosyaları: [Spring.Core, MySql.data, NHibernate, log4net]. Bu DLL dosyalarına, kendilerinin de kullandığı DLL dosyalarının kopyaları eşlik etmektedir:
- [CastleDynamicProxy, Iesi.Collections], NHibernate aracı için
- [antlr.runtime, Common.Logging], Spring aracı için
- [pam-dao-nhibernate.dll.config] dosyası, [App.config] yapılandırma dosyasının bir kopyasıdır. Bu kopyalama işlemini VS gerçekleştirir. Çalıştırma sırasında [App.config] dosyası değil, [pam-dao-nhibernate.dll.config] dosyası kullanılır.
DLL ve [pam-dao-nhibernate.dll] dosyalarını, 2.4.6 sürümündeki [NUnit-Gui] aracıyla yükleyip testleri gerçekleştiriyoruz:

Yukarıda, testler başarıyla tamamlanmıştır.
Uygulama ödevi:
[PamDaoNHibernate] sınıfındaki testleri makinede çalıştırın.- Farklı [App.config] yapılandırma dosyalarını kullanarak farklı SGBD sunucuları (Firebird, MySQL, Postgres, SQL Sunucusu) çalıştırın
7.3.5. [dao] katmanınd 'in DLL'ten oluşturulması
[PamDaoNHibernate] sınıfı yazıldıktan ve test edildikten sonra, [dao] katmanından DLL şu şekilde oluşturulacaktır:
![]() |
- [1], test programları proje derlemesinden hariç tutulur
- [2,3], proje yapılandırması
- [4], proje oluşturma
- DLL dosyası, [bin/Release] ve [5] klasörlerinde oluşturulur. Bunu, [lib] [6] klasöründe zaten bulunan DLL dosyasına ekliyoruz:
![]() |
7.4. İş katmanı
[SimuPaie] uygulamasının genel mimarisine geri dönelim:
![]() |
Artık [dao] katmanının hazır olduğunu ve DLL ile [pam-dao-nhibernate.dll] içinde kapsüllendiğini varsayıyoruz. Şimdi [metier] katmanına odaklanıyoruz. İş kurallarını, bu örnekte maaş hesaplama kurallarını uygulayan katman budur.
7.4.1. [metier] katmanının Visual Studio'daki projesi
İş katmanının Visual Studio projesi aşağıdaki gibi görünebilir:
![]() |
- [1] dosyasında, [App.config] dosyası tarafından yapılandırılan tüm proje
- [2] dosyasında, [metier] katmanı iki [entites, service] klasöründen oluşur. [tests] klasörü, bir konsol test programı (Main.cs) ve bir NUnit test programı (NUnit.cs) içerir.
- [3] dosyasında proje tarafından kullanılan referanslar yer almaktadır. Daha önce incelenen [dao] katmanına ait DLL ve [pam-dao-nhibernate] referanslarına dikkat edilmelidir.
7.4.2. [metier] katmanının [IPamMetier] arayüzü
Uygulamanın genel mimarisine geri dönelim:
![]() |
[metier] katmanı, [ui] katmanına hangi arayüzü sunmalıdır? Bu iki katman arasında hangi etkileşimler mümkündür? Kullanıcıya sunulacak web arayüzünü hatırlayalım:
![]() |
- Formun ilk görüntülendiği anda, [1]'te çalışanların listesi bulunmalıdır. Basit bir liste yeterlidir (Soyadı, Adı, SS). Seçilen çalışanla ilgili ek bilgilere (6 ila 11 numaralı bilgiler) erişmek için SS numarası gereklidir.
- 12 ila 15 numaralı bilgiler, çeşitli prim oranlarını gösterir.
- 16 ila 19 numaralı bilgiler, çalışanın endeksine bağlı ödeneklerdir
- 20 ila 24 numaralı bilgiler, kullanıcı tarafından girilen 1 ila 3 numaralı veriler temel alınarak hesaplanan maaş bileşenleridir.
[metier] katmanı tarafından [ui] katmanına sunulan [IPamMetier] arayüzü, yukarıdaki gereksinimleri karşılamalıdır. Birçok farklı arayüz seçeneği mevcuttur. Biz şu arayüzü öneriyoruz:
using Pam.Dao.Entites;
using Pam.Metier.Entites;
namespace Pam.Metier.Service {
public interface IPamMetier {
// tüm çalışan kimliklerinin listesi
Employe[] GetAllIdentitesEmployes();
// ------- maaş hesaplaması
FeuilleSalaire GetSalaire(string ss, double heuresTravaillées, int joursTravaillés);
}
}
- 7. satır: [1] açılır menüsünün doldurulmasını sağlayacak yöntem
- 10. satır: 6 ila 24 numaralı bilgileri elde etmeyi sağlayacak yöntem. Bu bilgiler, [FeuilleSalaire] türünde bir nesne içinde toplanmıştır.
7.4.3. [metier] katmanındaki varlıklar
Visual Studio projesindeki [entites] klasörü, iş sınıfı tarafından işlenen nesneleri içerir: [FeuilleSalaire] ve [ElementsSalaire].
![]() |
[FeuilleSalaire] sınıfı, önceki formdaki 6 ila 24 numaralı bilgileri kapsar:
using Pam.Dao.Entites;
namespace Pam.Metier.Entites {
public class FeuilleSalaire {
// otomatik özellikler
public Employe Employe { get; set; }
public Cotisations Cotisations { get; set; }
public ElementsSalaire ElementsSalaire { get; set; }
// ToString
public override string ToString() {
return string.Format("[{0},{1},{2}", Employe, Cotisations, ElementsSalaire);
}
}
}
- 8. satır: Maaşı hesaplanan çalışana ait 6 ila 11 numaralı bilgiler ve ek ödemelerine ait 16 ila 19 numaralı bilgiler. Burada, bir [Employe] nesnesinin, çalışanın ek ödemelerini temsil eden bir [Indemnites] nesnesini içerdiğini unutmamak gerekir.
- 9. satır: 12 ila 15 numaralı bilgiler
- 10. satır: 20 ile 24 arasındaki bilgiler
- 13-15. satırlar: [ToString] yöntemi
[ElementsSalaire] sınıfı , formdaki 20 ila 24 numaralı bilgileri kapsar:
namespace Pam.Metier.Entites {
public class ElementsSalaire {
// otomatik özellikler
public double SalaireBase { get; set; }
public double CotisationsSociales { get; set; }
public double IndemnitesEntretien { get; set; }
public double IndemnitesRepas { get; set; }
public double SalaireNet { get; set; }
// ToString
public override string ToString() {
return string.Format("[{0} : {1} : {2} : {3} : {4} ]", SalaireBase, CotisationsSociales, IndemnitesEntretien, IndemnitesRepas, SalaireNet);
}
}
}
- satır 4-8: 3.2. paragrafında açıklanan iş kurallarında belirtildiği şekilde maaş bileşenleri.
- 4. satır: Çalışanın, çalışılan saat sayısına bağlı olarak hesaplanan temel maaşı
- 5. satır: bu temel maaştan kesilen primler
- 6. ve 7. satırlar: Çalışanın endeksine ve çalışılan gün sayısına bağlı olarak temel maaşa eklenecek ek ödemeler
- satır 8: ödenecek net maaş
- satır 12-15: Sınıfın [ToString] yöntemi.
7.4.4. [metier] katmanının uygulanması
![]() |
[IPamMetier] arayüzünü iki sınıfla uygulayacağız:
- [AbstractBasePamMetier], [IPamMetier] arayüzünün veri erişimini uygulayacağımız soyut bir sınıftır. Bu sınıf, [dao] katmanına bir referansa sahip olacaktır.
- [PamMetier], [AbstractBasePamMetier] sınıfından türetilmiş bir sınıftır ve [IPamMetier] arayüzünün iş kurallarını uygulayacaktır. Bu sınıf, [dao] katmanından habersiz olacaktır.
[AbstractBasePamMetier] sınıfı şu şekilde olacaktır:
using Pam.Dao.Entites;
using Pam.Dao.Service;
using Pam.Metier.Entites;
namespace Pam.Metier.Service {
public abstract class AbstractBasePamMetier : IPamMetier {
// veri erişim nesnesi
public IPamDao PamDao { get; set; }
// tüm çalışan kimliklerinin listesi
public Employe[] GetAllIdentitesEmployes() {
return PamDao.GetAllIdentitesEmployes();
}
// belirli bir çalışan ve primleri
protected Employe GetEmploye(string ss) {
return PamDao.GetEmploye(ss);
}
// primler
protected Cotisations GetCotisations() {
return PamDao.GetCotisations();
}
// maaş hesaplaması
public abstract FeuilleSalaire GetSalaire(string ss, double heuresTravaillées, int joursTravaillés);
}
}
- 5. satır: Sınıf, [metier] katmanındaki tüm sınıflar ve arayüzler gibi [Pam.Metier.Service] ad alanına aittir.
- 6. satır: Sınıf soyuttur (abstract özniteliği) ve [IPamMetier] arayüzünü uygular
- 9. satır: Sınıf, [dao] katmanına bir kamu özelliğiyle referans tutar
- 12-14. satırlar: [IPamMetier] arayüzünün [GetAllIdentitesEmployes] yönteminin uygulaması – [dao] katmanındaki aynı adlı yöntemi kullanır
- satır 17-19: [dao] katmanındaki aynı adlı yöntemi çağıran dahili (protected) [GetEmploye] yöntemi – türetilmiş sınıfların bu yönteme, yöntem kamuya açık olmadan erişebilmesi için protected olarak tanımlanmıştır.
- 22-24. satırlar: [GetCotisations] katmanındaki aynı adlı yöntemi çağıran dahili (protected) [GetCotisations] yöntemi
- 27. satır: [IPamMetier] arayüzünün [GetSalaire] yönteminin soyut uygulaması (abstract özniteliği).
Maaş hesaplaması, aşağıdaki [PamMetier] sınıfı tarafından gerçekleştirilir:
using System;
using Pam.Dao.Entites;
using Pam.Metier.Entites;
namespace Pam.Metier.Service {
public class PamMetier : AbstractBasePamMetier {
// maaş hesaplaması
public override FeuilleSalaire GetSalaire(string ss, double heuresTravaillées, int joursTravaillés) {
// SS: çalışanın SS numarası
// HeuresTravaillées: çalışılan saat sayısı
// Çalışılan Günler: çalışılan gün sayısı
// çalışanı, ödenekleriyle birlikte alır
...
// Çeşitli prim oranlarını alırız
...
// maaş bileşenlerini hesaplar
...
// maaş bordrosu oluşturulur
return ...;
}
}
}
- 7. satır: Sınıf, [AbstractBasePamMetier]'ten türetilmiştir ve bu nedenle [IPamMetier] arayüzünü uygular
- 10. satır: Uygulanacak [GetSalaire] yöntemi
Soru: [GetSalaire] yönteminin kodunu yazınız.
7.4.5. [metier] katmanının konsol testi
[metier] katmanının Visual Studio projesini hatırlayalım:
![]() |
Yukarıdaki [Main] test programı, [IPamMetier] arayüzündeki yöntemleri test eder. Basit bir örnek şu şekilde olabilir:
using System;
using Pam.Dao.Entites;
using Pam.Metier.Service;
using Spring.Context.Support;
namespace Pam.Metier.Tests {
class MainPamMetierTests {
public static void Main() {
try {
// [metier] katmanının örneği oluşturulur
IPamMetier pamMetier = ContextRegistry.GetContext().GetObject("pammetier") as IPamMetier;
// maaş bordro hesaplamaları
Console.WriteLine(pamMetier.GetSalaire("260124402111742", 30, 5));
Console.WriteLine(pamMetier.GetSalaire("254104940426058", 150, 20));
try {
Console.WriteLine(pamMetier.GetSalaire("xx", 150, 20));
} catch (PamException ex) {
Console.WriteLine(string.Format("PamException : {0}", ex.Message));
}
} catch (Exception ex) {
Console.WriteLine(string.Format("Exception : {0}", ex.ToString()));
}
// ara
Console.ReadLine();
}
}
}
- 11. satır: Spring tarafından [metier] katmanının örneklenmesi.
- 13-14. satırlar: [IPamMetier] arayüzünün [GetSalaire] yönteminin test edilmesi
- 15-22. satırlar: bir istisna oluştuğunda [GetSalaire] yönteminin test edilmesi
Test programı, aşağıdaki [App.config] yapılandırma dosyasını kullanır:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<!-- yapılandırma bölümleri -->
<configSections>
<section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler,log4net" />
<sectionGroup name="spring">
<section name="objects" type="Spring.Context.Support.DefaultSectionHandler, Spring.Core" />
<section name="context" type="Spring.Context.Support.ContextHandler, Spring.Core" />
</sectionGroup>
<section name="hibernate-configuration" type="NHibernate.Cfg.ConfigurationSectionHandler, NHibernate" />
</configSections>
<!-- Spring yapılandırması -->
<spring>
<context>
<resource uri="config://spring/objects" />
</context>
<objects xmlns="http://www.springframework.net">
<object id="pamdao" type="Pam.Dao.Service.PamDaoNHibernate, pam-dao-nhibernate" init-method="init" destroy-method="destroy"/>
<object id="pammetier" type="Pam.Metier.Service.PamMetier, pam-metier-dao-nhibernate" >
<property name="PamDao" ref="pamdao"/>
</object>
</objects>
</spring>
<!-- yapılandırma NHibernate -->
<hibernate-configuration xmlns="urn:nhibernate-configuration-2.2">
....
</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. Program aracılığıyla etkinleştirilmeleri gerekir
avec l'instruction log4net.Config.XmlConfigurator.Configure();
! -->
<log4net>
...
</log4net>
</configuration>
Bu dosya, [dao] katman projesinde (bkz. paragraf 7.3.2) kullanılan [App.config] dosyasıyla, aşağıdaki ayrıntılar dışında aynıdır:
- 20. satır: "pamdao" kimlikli nesnenin türü [Pam.Dao.Service.PamDaoNHibernate]'tir ve [pam-dao-nhibernate] derlemesinde bulunur. [dao] katmanı, daha önce incelenen katmandır.
- 21-23. satırlar: "pammetier" kimliğine sahip nesnenin türü [Pam.Metier.Service.PamMetier]'tir ve [pam-metier-dao-nhibernate] derlemesinde bulunur. Proje bu şekilde yapılandırılmalıdır:
![]() |
- 22. satır: Spring tarafından örneklendirilen [PamMetier] nesnesi, [dao] katmanına bir referans olan [PamDao] adlı bir public özelliğe sahiptir. Bu özellik, 20. satırda oluşturulan [dao] katmanına ait referansla başlatılır.
6.2. paragrafta açıklanan veritabanı kullanılarak yapılan çalıştırma, konsolda aşağıdaki sonucu verir:
- 1-2. satırlar: talep edilen 2 maaş bordrosu
- 3. satır: [PamException] tipi istisna, mevcut olmayan bir çalışan nedeniyle oluştu.
7.4.6. İş mantığı katmanının birim testleri
Önceki test görseldi: Ekranda beklenen sonuçların elde edildiğini kontrol ediyorduk. Şimdi NUnit numaralı görsel olmayan testlere geçiyoruz.
[metier] projesinin Visual Studio projesine geri dönelim:
![]() |
- [1]'te, NUnit test programı
- [2]'e, DLL'teki referans ise [nunit.framework]'e
![]() |
- [3,4]'e dönüştürüldüğünde, proje derlemesi DLL ve [pam-metier-dao-nhibernate.dll] dosyalarını oluşturacaktır.
- [5]'te, [NUnit.cs] dosyası [pam-metier-dao-nhibernate.dll] derlemesine dahil edilecek, ancak [Main.cs] ve [6] dosyaları dahil edilmeyecektir.
'in NUnit test sınıfı şu şekildedir:
using NUnit.Framework;
using Pam.Dao.Entites;
using Pam.Metier.Entites;
using Pam.Metier.Service;
using Spring.Context.Support;
namespace Pam.Metier.Tests {
[TestFixture()]
public class NunitTestPamMetier : AssertionHelper {
// [metier] katmanı test edilecek
private IPamMetier pamMetier;
// oluşturucu
public NunitTestPamMetier() {
// [dao] katmanının örneklenmesi
pamMetier = ContextRegistry.GetContext().GetObject("pammetier") as IPamMetier;
}
[Test]
public void GetAllIdentitesEmployes() {
// çalışan sayısının doğrulanması
Expect(2, EqualTo(pamMetier.GetAllIdentitesEmployes().Length));
}
[Test]
public void GetSalaire1() {
// maaş bordrosu hesaplama
FeuilleSalaire feuilleSalaire = pamMetier.GetSalaire("254104940426058", 150, 20);
// kontroller
Expect(368.77, EqualTo(feuilleSalaire.ElementsSalaire.SalaireNet).Within(1E-06));
// var olmayan bir çalışanın maaş bordrosu
bool erreur = false;
try {
feuilleSalaire = pamMetier.GetSalaire("xx", 150, 20);
} catch (PamException) {
erreur = true;
}
Expect(erreur, True);
}
}
}
- 13. satır: özel alan [pamMetier], [metier] katman erişim arayüzünün bir örneğidir. Bu alanın türünün bir sınıf değil, bir arayüz olduğu unutulmamalıdır. Bu, [PamMetier] örneğinin yalnızca [IPamMetier] arayüzüne ait yöntemlere erişim sağladığı anlamına gelir.
- 16-19. satırlar: Sınıfın oluşturucusu, Spring ve [App.config] yapılandırma dosyasını kullanarak [pamMetier] özel alanını başlatır.
- 23-26. satırlar: [GetAllIdentitesEmployes] yöntemini test eder
- 29-42. satırlar: [GetSalaire] yöntemini test eder
Yukarıdaki proje, [bin/Release] klasöründe DLL ve [pam-metier.dll] dosyalarını oluşturur.
![]() |
[bin/Release] klasörü ayrıca şunları içerir:
- Proje referanslarının bir parçası olan ve [Copie locale] özniteliği "true" olarak ayarlanmış DLL dosyaları: [Spring.Core, MySql.data, NHibernate, log4net, pam-dao-nhibernate]. Bu DLL dosyalarına, kendilerinin de kullandığı DLL dosyalarının kopyaları eşlik etmektedir:
- [CastleDynamicProxy, Iesi.Collections], NHibernate aracı için
- [antlr.runtime, Common.Logging], Spring aracı için
- [pam-metier-dao-nhibernate.dll.config] dosyası, [App.config] yapılandırma dosyasının bir kopyasıdır.
DLL ve [pam-metier-dao-nhibernate.dll] dosyalarını [NUnit-Gui, version 2.4.6] aracıyla yükleyip testleri çalıştırıyoruz:

Yukarıda, testler başarıyla tamamlanmıştır.
Uygulama ödevi:
[PamMetier] sınıfındaki testleri makinede uygulayın.- Farklı App.config yapılandırma dosyalarını kullanarak farklı SGBD'leri (Firebird, MySQL, Postgres, SQL Server) çalıştırın
7.4.7. [metier] katmanının DLL dosyasının oluşturulması
[PamMetier] sınıfı yazıldıktan ve test edildikten sonra, 7.3. paragrafında açıklanan yöntemi izleyerek [metier] katmanından DLL ve [pam-metier-dao-nhibernate.dll] sınıfları oluşturulacaktır.5 DLL dosyasına [Main.cs] ve [NUnit.cs] test programlarının dahil edilmemesine dikkat edilecektir. Daha sonra bu katman, DLL ve [1] katmanlarının bulunduğu [lib] klasörüne yerleştirilecektir.
![]() |
7.5. [web] katmanı
[SimuPaie] uygulamasının genel mimarisine geri dönelim:
![]() |
[dao] ve [métier] katmanlarının oluşturulduğunu ve DLL ile [pam-dao-nhibernate, pam-metier-dao-nhibernate.dll] içinde kapsandığını varsayıyoruz. Şimdi web katmanını açıklayacağız.
7.5.1. [web] katmanının Visual Web Developer projesi
![]() |
- [1]'te, projenin tamamı:
- [Global.asax]: web uygulamasının başlatılması sırasında örneklendirilen ve uygulamanın başlatılmasını sağlayan sınıf
- [Default.aspx]: web form sayfası
- [2]'te, web uygulaması için gerekli olan DLL'ler. Daha önce oluşturulmuş olan [dao] ve [metier] katmanlarının DLL'lerine dikkat edilmelidir.
7.5.2. Uygulamanın yapılandırılması
Uygulamayı yapılandıran [Web.config] dosyası, daha önce incelenen [metier] katmanını yapılandıran [App.config] dosyasıyla aynı verileri tanımlar. Bu veriler, [Web.config] dosyasının önceden oluşturulmuş koduna yerleştirilmelidir:
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<configSections>
<sectionGroup name="system.web.extensions" type="System.Web.Configuration.SystemWebExtensionsSectionGroup, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35">
..........
</sectionGroup>
<sectionGroup name="spring">
<section name="context" type="Spring.Context.Support.ContextHandler, Spring.Core" />
<section name="objects" type="Spring.Context.Support.DefaultSectionHandler, Spring.Core" />
</sectionGroup>
<section name="hibernate-configuration" type="NHibernate.Cfg.ConfigurationSectionHandler, NHibernate" />
<section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler,log4net" />
</configSections>
<!-- Spring yapılandırması -->
<spring>
<context>
<resource uri="config://spring/objects" />
</context>
<objects xmlns="http://www.springframework.net">
<object id="pamdao" type="Pam.Dao.Service.PamDaoNHibernate, pam-dao-nhibernate" init-method="init" destroy-method="destroy"/>
<object id="pammetier" type="Pam.Metier.Service.PamMetier, pam-metier-dao-nhibernate" >
<property name="PamDao" ref="pamdao"/>
</object>
</objects>
</spring>
<!-- 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-dao-nhibernate"/>
</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. Program aracılığıyla etkinleştirilmeleri gerekir
avec l'instruction log4net.Config.XmlConfigurator.Configure();
! -->
<log4net>
....
</log4net>
<appSettings/>
<connectionStrings/>
<system.web>
....
....
</configuration>
9-12, 18-28 ve 31-44. satırlarda, [metier] katmanının [App.config] dosyasında açıklanan Spring ve NHibernate yapılandırması yer almaktadır (bkz. 7.4.5. paragraf).
Global.asax.cs
using System;
using Pam.Dao.Entites;
using Pam.Metier.Service;
using Spring.Context.Support;
namespace pam_v3
{
public class Global : System.Web.HttpApplication
{
// --- uygulamanın statik verileri ---
public static Employe[] Employes;
public static IPamMetier PamMetier = null;
public static string Msg;
public static bool Erreur = false;
// uygulamanın başlatılması
public void Application_Start(object sender, EventArgs e)
{
// yapılandırma dosyasının işlenmesi
try
{
// [metier] katmanının örneklenmesi
PamMetier = ContextRegistry.GetContext().GetObject("pammetier") as IPamMetier;
// çalışanların basitleştirilmiş listesi
Employes = PamMetier.GetAllIdentitesEmployes();
// başarılı
Msg = "Base chargée...";
}
catch (Exception ex)
{
// hata kaydedildi
Msg = string.Format("L'erreur suivante s'est produite lors de l'accès à la base de données : {0}", ex);
Erreur = true;
}
}
}
}
Şunu hatırlatmak isteriz ki:
- [Global.asax.cs] sınıfı, uygulamanın başlatılması sırasında örneklenir ve bu örneğe tüm kullanıcıların tüm istekleri tarafından erişilebilir. Dolayısıyla, 11-14. satırlardaki statik alanlar tüm kullanıcılar arasında paylaşılır.
- [Application_Start] yöntemi, sınıfın örneklendirilmesinden sonra yalnızca bir kez yürütülür. Uygulamanın başlatılması genellikle bu yöntemde gerçekleştirilir.
Tüm kullanıcılar tarafından paylaşılan veriler şunlardır:
- 11. satır: Tüm çalışanların basitleştirilmiş listesini (SS, NOM, PRENOM) depolayacak olan [Employe] türündeki nesnelerden oluşan dizi
- 12. satır: DLL ve [pam-metier-dao-nhibernate.dll] içinde kapsüllenmiş [metier] katmanına bir referans
- 13. satır: Başlatma işleminin nasıl sonuçlandığını (başarılı mı yoksa hata mı) belirten bir mesaj
- 14. satır: Başlatma işleminin hata ile sonuçlanıp sonuçlanmadığını belirten bir boole değeri.
[Application_Start] dosyasında:
- 23. satır: Spring, [metier] ve [dao] katmanlarını oluşturur ve [metier] katmanına bir referans döndürür. Bu referans, 12. satırdaki [PamMetier] statik alanında saklanır.
- 25. satır: Çalışan tablosu, [metier] katmanından istenir
- 27. satır: İşlem başarılı olduğunda görüntülenen mesaj
- 32. satır: Hata durumunda görüntülenen mesaj
7.5.3. [Default.aspx] formu
Form, sürüm 2'ye aittir.

Soru: Sürüm 2'deki [Default.aspx.cs] sayfasındaki C# kodundan esinlenerek, sürüm 3'ün [Default.aspx.cs] kodunu yazınız. Tek fark, maaş hesaplamasındadır. Sürüm 2'de veritabanından bilgi almak için API ve ADO.NET kullanılırken, burada [metier] katmanındaki GetSalaire yöntemi kullanılacaktır.
Uygulama:
önceki web uygulamasını bir bilgisayarda çalıştırın- Farklı [Web.config] yapılandırma dosyalarını kullanarak farklı SGBD'leri (Firebird, MySQL, Postgres, SQL Server) kullanmak





























