2. Bölüm 2
2.1. Introduction
Öncelikle 1. bölümde yapılanları ve özellikle kullanılan üç katmanlı [web, domain, dao] mimarisini hatırlatarak başlayacağız. Önerilen çözümde, [dao] katmanı bir test katmanıydı: veri kaynağı bir [ArrayList] nesnesi ile uygulanmıştı. Bu makalede, veriler bir SGBD nesnesinde bulunduğunda, [dao] katmanının çeşitli olası uygulamalarını ele alacağız.
Kullanılan araçlar:
- Firebird SGBD - bkz. ek, paragraf 3.5.
- SGBD MSDE (Microsoft Data Engine) - bkz. ek, paragraf 3.12.
- IBExpert, SGBD Firebird'ü grafiksel olarak yönetmek için kişisel sürüm - bkz. ek, paragraf 3.6.
- EMS MS SQL Manager, SGBD MSDE'i grafiksel olarak yönetmek için - ek bölüm 3.14'e bakınız.
- Ibatis SqlMap, SGBD'in veri erişim katmanı için - bkz. paragraf 2.5.6.2.
Başlangıç-orta-ileri düzey ölçeğinde, bu belge [intermédiaire-avancé] bölümünde yer almaktadır. Bu belgeyi anlamak için çeşitli ön koşullar gereklidir. Bunlardan bazıları, benim yazdığım belgelerde bulunabilir. Bu durumda, bunlara atıfta bulunuyorum. Elbette bu sadece bir öneridir ve okuyucu kendi tercih ettiği belgeleri kullanabilir.
- VB.net dili: [Introduction au langage VB.NET par l'exemple ]
- VB.net ile web programlama: [Développement WEB avec ASP.NET 1.1 ]
- Spring'in IoC özelliğinin kullanımı: [Spring IoC pour .NET ]
- Ibatis belgeleri SqlMap : [http://prdownloads.sourceforge.net/ibatisnet/DevGuide.pdf?download]
- Firebird belgeleri: [http://firebird.sourceforge.net/pdfmanual/Firebird-1.5-QuickStart.pdf]
- Spring.net belgeleri: [http://www.springframework.net/documentation.html]
2.2. Web uygulaması - Özet
Burada, 1. bölümde incelenen basitleştirilmiş e-ticaret web uygulamasının bileşenlerini sunuyoruz. Bu uygulama, web kullanıcılarına şunları sağlar:
- bir veritabanından gelen ürün listesini görüntüleyebilir
- bazı ürünleri elektronik sepetlerine ekleyebilme
- sepeti onaylayabilmelerini sağlar. Bu onay işleminin tek etkisi, satın alınan ürünlerin stok bilgilerini veritabanında güncellemektir.
2.2.1. Uygulamanın görünümleri
Kullanıcıya sunulan farklı görünümler şunlardır:
![]() |
![]() |
![]() |
- Uygulamadaki tüm hataları bildiren [ERREURS] görünümü

2.2.2. Uygulamanın genel mimarisi
- bölümde geliştirilen uygulama, üç katmanlı bir mimariye sahiptir:
![]() |
- Arayüzlerin kullanılmasıyla üç katman birbirinden bağımsız hale getirilmiştir
- farklı katmanların entegrasyonu Spring ile gerçekleştirilmiştir
- Her katman ayrı ad alanlarına sahiptir: web (UI katmanı), domain (iş katmanı) ve dao (veri erişim katmanı).
Uygulama, MVC mimarisine (Model - Görünüm - Denetleyici) uygundur. Yukarıdaki katman şemasını ele alırsak, MVC mimarisi bu şemaya şu şekilde entegre edilir:
![]() |
Bir istemciden gelen isteğin işlenmesi aşağıdaki adımlara göre gerçekleşir:
- müşteri, denetleyiciye bir istek gönderir. Bu denetleyici, burada özel bir rol üstlenen bir .aspx sayfasıdır. Müşterilerin tüm isteklerini bu sayfa üzerinden alır. Bu, uygulamanın giriş kapısıdır. MVC'teki C harfi budur.
- Denetleyici bu talebi işler. Bunu yapmak için iş katmanının yardımına ihtiyaç duyabilir; bu, MVC yapısında M modeli olarak adlandırılır.
- Denetleyici, iş katmanından bir yanıt alır. Müşterinin talebi işlenmiştir. Bu, birkaç farklı yanıtı içerebilir. Klasik bir örnek,
- isteğin düzgün bir şekilde işlenememesi durumunda bir hata sayfası
- aksi takdirde bir onay sayfası
- denetleyici, müşteriye gönderilecek yanıtı (= görünüm) seçer. Bu, çoğunlukla dinamik öğeler içeren bir sayfadır. Denetleyici, bu öğeleri görünüme sağlar.
- Görünüm, müşteriye gönderilir. Bu, MVC'teki V'dir.
2.2.3. Şablon
MVC'teki M modeli burada aşağıdaki öğelerden oluşur:
- iş sınıfları
- veri erişim sınıfları
- veritabanı
2.2.3.1. Veritabanı
Veritabanı, aşağıdaki SQL komutlarıyla oluşturulan ARTICLES adlı tek bir tablo içerir:
CREATE TABLE ARTICLES (
ID INTEGER NOT NULL,
NOM VARCHAR(20) NOT NULL,
PRIX NUMERIC(15,2) NOT NULL,
STOCKACTUEL INTEGER NOT NULL,
STOCKMINIMUM INTEGER NOT NULL
);
/* kısıtlamalar */
ALTER TABLE ARTICLES ADD CONSTRAINT CHK_ID check (ID>0);
ALTER TABLE ARTICLES ADD CONSTRAINT CHK_PRIX check (PRIX>=0);
ALTER TABLE ARTICLES ADD CONSTRAINT CHK_STOCKACTUEL check (STOCKACTUEL>=0);
ALTER TABLE ARTICLES ADD CONSTRAINT CHK_STOCKMINIMUM check (STOCKMINIMUM>=0);
ALTER TABLE ARTICLES ADD CONSTRAINT CHK_NOM check (NOM<>'');
ALTER TABLE ARTICLES ADD CONSTRAINT UNQ_NOM UNIQUE (NOM);
/* birincil anahtar */
ALTER TABLE ARTICLES ADD CONSTRAINT PK_ARTICLES PRIMARY KEY (ID);
bir ürünü benzersiz bir şekilde tanımlayan birincil anahtar | |
ürün adı | |
ürünün fiyatı | |
mevcut stok durumu | |
yeniden tedarik siparişinin verilmesi gereken stok seviyesi |
2.2.3.2. Modelin ad alanları
M modeli iki ad alanı şeklinde sunulur:
- istia.st.articles.dao: [dao] katmanının veri erişim sınıflarını içerir
- istia.st.articles.domain: [domain] katmanının iş sınıflarını içerir
Bu ad alanlarının her biri, kendisine ait bir "assembly" dosyası içinde yer alır:
assembly | contenu | rôle |
webarticles-dao | - [IArticlesDao]: [dao] katmanına erişim arayüzü. [domain] katmanının gördüğü tek arayüz budur. Başka bir arayüz görmez. - [Article]: bir ürünü tanımlayan sınıf - [ArticlesDaoArrayList]: [IArticlesDao] arayüzünün, [ArrayList] sınıfı ile birlikte uygulanmasını sağlayan sınıf | veri erişim katmanı - tamamen web uygulamasının 3-katmanlı mimarisinin [dao] katmanında yer alır |
webarticles-domain | - [IArticlesDomain]: [domain] katmanına erişim arayüzüdür. Web katmanının gördüğü tek arayüzdür. Başka bir arayüz görmez. - [AchatsArticles]: [IArticlesDomain]'i uygulayan bir sınıf - [Achat]: Bir müşterinin satın alma işlemini temsil eden sınıf - [Panier]: Bir müşterinin tüm satın alımlarını temsil eden sınıf | web üzerindeki satın alma işlemlerinin modelini temsil eder - tamamen web uygulamasının 3 katmanlı mimarisinin [domain] katmanında yer alır |
2.2.4. [webarticles] uygulamasının dağıtımı ve testleri
2.2.4.1. Dağıtım
Makalenin 1. bölümünde geliştirilen uygulamayı [runtime] adlı bir klasöre dağıtıyoruz:
![]() | ![]() |
![]() |
Açıklamalar:
[runtime] klasörü üç dosya ve iki alt klasör içerir:
- [global.asax] ve [main.aspx] denetleyicileri
- [web.config] yapılandırma dosyası
- [bin] klasörü, şunları içerir:
- üç katmanın DLL dosyaları: [webarticles-dao.dll], [webarticles-domain.dll], [webarticles-web.dll]
- Spring için gerekli dosyalar: [Spring-Core.*], [log4net.dll]
- farklı görünümlerin sunum kodunu içeren [vues] klasörü.
- .vb kod dosyalarının bulunması gereksizdir, çünkü bunların derlenmiş halleri DLL içinde bulunmaktadır.
2.2.4.2. Testler
[Cassini] web sunucusunu şu şekilde yapılandırıyoruz:

ile:
Fiziksel Yol: D:\data\serge\travail\2004-2005\aspnet\webarticles-010405\runtime\
Sanal Yol: /webarticles
Bir tarayıcı kullanarak URL adresine erişiyoruz. [http://localhost/webarticles/main.aspx]

[dao] katmanının, makaleleri bir [ArrayList] nesnesinde depolayan bir sınıf tarafından uygulandığını hatırlayalım. Bu sınıf, başlangıçta dört makaleden oluşan bir liste oluşturur. Yukarıdaki görünümden yola çıkarak, işlemleri gerçekleştirmek için menüdeki bağlantıları kullanıyoruz. İşte bunlardan birkaçı. Soldaki sütun müşterinin talebini, sağdaki sütun ise ona verilen yanıtı temsil eder.
![]() | ![]() |
![]() | ![]() |
![]() | ![]() |
![]() | ![]() |
![]() | ![]() |
![]() | ![]() |
![]() | ![]() |
![]() | ![]() |
![]() | ![]() |
![]() | ![]() |
![]() | ![]() |
![]() | ![]() |
2.2.5. [dao] katmanının yeniden ele alınması
[dao] katmanının ilk uygulamamızda, verilere erişim sağlayan [IArticlesDao] arayüzü, makaleleri bir [ArrayList] nesnesinde depolayan bir sınıf aracılığıyla uygulanmıştı. Bu sayede bu katman üzerinde fazla durmamıza gerek kalmadı ve önemli olanın katmanın uygulaması değil, arayüzü olduğunu gösterebildik. Böylece işlevsel bir web uygulaması geliştirebildik. Bu uygulama, [web], [domain] ve [dao] olmak üzere üç katmandan oluşmaktadır. Burada, [dao] katmanının farklı uygulamalarını sunacağız. Bunların her biri, [domain] ve [web] katmanlarında herhangi bir değişiklik yapılmasına gerek kalmadan mevcut [dao] katmanının yerini alabilir. Bu esneklik şu nedenden kaynaklanmaktadır:
- [domain] katmanı somut bir sınıfa değil, [IArticlesDao] arayüzüne yöneliktir
- Spring sayesinde, [domain] katmanından [IArticlesDao] arayüzünün uygulama sınıfının adını gizleyebildik.
2.2.5.1. [dao] katmanının öğeleri
Yeni uygulamalarda korunacak olan [dao] katmanının bazı öğelerini hatırlayalım:
- - [IArticlesDao]: [dao] katmanına erişim arayüzü
- - [Article]: bir öğeyi tanımlayan sınıf
2.2.5.2. [Article] sınıfı
Bir makaleyi tanımlayan sınıf şöyledir:
Imports System
Namespace istia.st.articles.dao
Public Class Article
' özel alanlar
Private _id As Integer
Private _nom As String
Private _prix As Double
Private _stockactuel As Integer
Private _stockminimum As Integer
' ürün kimliği
Public Property id() As Integer
Get
Return _id
End Get
Set(ByVal Value As Integer)
If Value <= 0 Then
Throw New Exception("Le champ id [" + Value.ToString + "] est invalide")
End If
Me._id = Value
End Set
End Property
' ürün adı
Public Property nom() As String
Get
Return _nom
End Get
Set(ByVal Value As String)
If Value Is Nothing OrElse Value.Trim.Equals("") Then
Throw New Exception("Le champ nom [" + Value + "] est invalide")
End If
Me._nom = Value
End Set
End Property
' ürün fiyatı
Public Property prix() As Double
Get
Return _prix
End Get
Set(ByVal Value As Double)
If Value < 0 Then
Throw New Exception("Le champ prix [" + Value.ToString + "] est invalide")
End If
Me._prix = Value
End Set
End Property
' ürünün mevcut stoğu
Public Property stockactuel() As Integer
Get
Return _stockactuel
End Get
Set(ByVal Value As Integer)
If Value < 0 Then
Throw New Exception("Le champ stockActuel [" + Value.ToString + "] est invalide")
End If
Me._stockactuel = Value
End Set
End Property
' ürün minimum stoğu
Public Property stockminimum() As Integer
Get
Return _stockminimum
End Get
Set(ByVal Value As Integer)
If Value < 0 Then
Throw New Exception("Le champ stockMinimum [" + Value.ToString + "] est invalide")
End If
Me._stockminimum = Value
End Set
End Property
' varsayılan üretici
Public Sub New()
End Sub
' özelliklere sahip üretici
Public Sub New(ByVal id As Integer, ByVal nom As String, ByVal prix As Double, ByVal stockactuel As Integer, ByVal stockminimum As Integer)
Me.id = id
Me.nom = nom
Me.prix = prix
Me.stockactuel = stockactuel
Me.stockminimum = stockminimum
End Sub
' ürün tanımlama yöntemi
Public Overrides Function ToString() As String
Return "[" + id.ToString + "," + nom + "," + prix.ToString + "," + stockactuel.ToString + "," + stockminimum.ToString + "]"
End Function
End Class
End Namespace
Bu sınıf şunları sunar:
- bir öğenin 5 bilgisini belirlemeye yarayan bir oluşturucu: [id, nom, prix, stockactuel, stockminimum]
- bu 5 bilgiyi okumak ve yazmak için kullanılan genel özellikler.
- ürüne girilen verilerin doğrulanması. Verilerde hata olması durumunda bir istisna atılır.
- bir makalenin değerini karakter dizesi biçiminde elde etmeyi sağlayan toString yöntemi. Bu, genellikle bir uygulamanın hata ayıklamasında yararlıdır.
2.2.5.3. [IArticlesDao] arayüzü
[IArticlesDao] arayüzü şu şekilde tanımlanmıştır:
Imports System
Imports System.Collections
Namespace istia.st.articles.dao
Public Interface IArticlesDao
' tüm ürünlerin listesi
Function getAllArticles() As IList
' ürün ekler
Function ajouteArticle(ByVal unArticle As Article) As Integer
' ürünü sil
Function supprimeArticle(ByVal idArticle As Integer) As Integer
' ürünü düzenle
Function modifieArticle(ByVal unArticle As Article) As Integer
' ürün arar
Function getArticleById(ByVal idArticle As Integer) As Article
' tüm ürünleri sil
Sub clearAllArticles()
' bir ürünün stokunu değiştirir
Function changerStockArticle(ByVal idArticle As Integer, ByVal mouvement As Integer) As Integer
End Interface
End Namespace
Arayüzdeki farklı yöntemlerin işlevleri şunlardır:
veri kaynağındaki tüm makaleleri döndürür | |
veri kaynağını boşaltır | |
numarasıyla tanımlanan [Article] nesnesini döndürür | |
veri kaynağına bir öğe eklemeye izin verir | |
veri kaynağındaki bir öğeyi değiştirmeye olanak tanır | |
veri kaynağından bir öğeyi silmeye olanak tanır | |
veri kaynağındaki bir ürünün stokunu değiştirmeye olanak tanır |
Arayüz, istemci programlarına yalnızca imzalarıyla tanımlanan bir dizi yöntem sunar. Bu yöntemlerin gerçekte nasıl uygulanacağıyla ilgilenmez. Bu, uygulamaya esneklik kazandırır. İstemci programı, arayüzün belirli bir uygulamasına değil, arayüze çağrı yapar.
![]() |
Belirli bir uygulamanın seçimi, bir Spring yapılandırma dosyası aracılığıyla yapılır.
2.3. [ArticlesDaoPlainODBC] uygulama sınıfı
Verilerin bir ODBC kaynağında olduğunu varsayan [dao] katmanının yeni bir uygulamasını sunuyoruz. Windows ortamında, piyasadaki neredeyse tüm SGBD ürünlerinin bir ODBC sürücüsüne sahip olduğu bilinmektedir. Bu çözümün avantajı, uygulama için şeffaf bir şekilde SGBD sürücüsünü değiştirebilme imkanı sağlamasıdır. Bunun dezavantajı ise, tüm SGBD'lerde ortak olan özellikleri kullanan bir ODBC sürücüsünün, genellikle belirli bir SGBD'in tüm potansiyelini kullanmak üzere özel olarak yazılmış bir sürücüye göre daha düşük performans göstermesidir. ODBC kaynak kodunun oluşturulmasına ilişkin bir örnek için 3.7 numaralı paragrafa bakabilirsiniz.
2.3.1. Kod
2.3.1.1. İskelet
[ArticlesDaoPlainODBC] sınıfı, [IArticlesDao] arayüzünü şu şekilde uygular:
Açıklamalar:
- 3. satırda, .NET sınıflarını içeren ad alanı içe aktarılır; ODBC kaynaklarına erişim
- 11. satır - ODBC kaynağına olan bağlantıyı saklayacaktır
- 12. satır - veri kaynağının adını DSN olarak saklayacaktır
- satır 13-19 - sınıfın çeşitli yöntemleri tarafından kullanılan SQL sorgularını tanımlayan [OdbcCommand] türündeki özel değişkenler
- 22-27. satırlar - oluşturucu. Kod ile veri kaynağını birbirine bağlayacak olan [OdbcConnection] nesnesini oluşturmasına olanak tanıyan öğeleri alır
- 29-31. satırlar - bir ürün ekleme yöntemi
- satır 33-35 - bir ürünün stokunu değiştirme yöntemi
- satır 37-39 - ODBC veri kaynağındaki tüm ürünleri silen yöntem
- 41-43. satırlar - ODBC kaynağındaki tüm ürünlerin listesini alan yöntem
- 45-47. satırlar - belirli bir ürünü alan yöntem
- 49-51. satırlar - numarası bilinen bir ürünün belirli alanlarını değiştirmeye yarayan yöntem
- 53-55. satırlar - numarası bilinen bir ürünü silmeye yarayan yöntem
- satır 57-60 - veri kaynağı üzerinde bir [SELECT] çalıştırıp sonucunu döndüren yardımcı yöntem
- satır 62-64 - veri kaynağı üzerinde bir [INSERT, UPDATE, DELETE] komutunu çalıştırıp sonucunu döndüren yardımcı yöntem
2.3.1.2. Oluşturucu
Açıklamalar:
- 2. satır - Oluşturucu, bir ODBC kaynağına bağlanmak için ihtiyaç duyduğu üç bilgiyi alır: kaynağın DSN adı, bağlanmak için kullanılacak kimlik ve ilgili şifre.
- 8. satır - Hata mesajlarında tekrar verilebilmesi için kaynağın adı DSN kaydedilir.
- 9. satır - [OdbcConnection] nesnesi oluşturulur. Oluşturulan bir bağlantı, açık bir bağlantı değildir. Bağlantıyı açan, [open] yöntemidir.
- 12-19. satırlar - SQL sorguları, [OdbcCommand] nesneleri içinde hazırlanır. Bu, ihtiyaç duyulduğunda her seferinde bunları yeniden oluşturmamızı önleyecektir. Sorgulardaki ? biçimindeki formal parametreler, sorgu yürütülürken gerçek değerlerle değiştirilecektir.
2.3.1.3. executeQuery yöntemi
Açıklamalar:
- [executeQuery] yöntemi, aşağıdakileri yapan bir yardımcı yöntemdir:
- veri kaynağı üzerinde [SELECT id, nom, prix, stockactuel, stockminimum from ARTICLES ...] sorgusunu yürütür
- sonucu [Article] nesnelerinden oluşan bir liste biçiminde döndürür
- 1. satır - Yöntemin tek parametresi, yürütülecek [Select] isteğini içeren [OdbcCommand] nesnesidir.
- 7. satır - Bağlantı açılmıştır. Hata olsun ya da olmasın, 29. satırda kapatılacaktır.
- 9. satır - [Select]'in sonucunu işlemek için gerekli olan [OdbcDataReader] nesnesi oluşturulur
- 13-23. satırlar - [Select]'in her bir sonuç satırı, diğer öğelerle birlikte [ArrayList] nesnesine eklenecek olan [Article] nesnesine yerleştirilir
- makale listesi 25. satırda döndürülür
- Herhangi bir istisna işlenmez. Bu istisnalar, bu yöntemi çağıran kod tarafından işlenmelidir.
2.3.1.4. executeUpdate yöntemi
Açıklamalar:
- Yöntem, [Insert, Update, Delete] türünde bir istek olan SQL'i içeren bir [OdbcCommand] nesnesi alır.
- Bağlantı 5. satırda açılır. Bir istisna olsun ya da olmasın, 10. satırda kapatılır.
- Güncelleme isteği 7. satırda yürütülür. İsteğin sonucu, yani istek tarafından değiştirilen ARTICLES tablosundaki satır sayısı, hemen döndürülür.
2.3.1.5. ajouteArticle yöntemi
Açıklamalar:
- 1. satır - Yöntem, ODBC veri kaynağına eklenecek öğeyi alır. Bu işlemden etkilenen satır sayısını c.a.d olarak döndürür. 1 veya 0
- 3. ve 20. satırlar - Yöntem senkronize edilmiştir. Veri erişimiyle ilgili tüm yöntemler için durum böyledir. Bu, veri kaynağı üzerinde aynı anda yalnızca bir iş parçacığının çalışabileceği anlamına gelir. Bu muhtemelen fazla muhafazakar bir yaklaşımdır. Daha iyi alternatifler mevcuttur; özellikle bu işlemleri işlemlere dahil etmek gibi. Bu durumda, eşzamanlı erişimleri SGBD yönetir. Şu anda işlem kavramını dahil etmek istemedik. Spring, bunları [domain] katmanına dahil etme imkanı sunar. Belki başka bir makalede bu konuya tekrar değinme fırsatımız olur.
- 5-12. satırlarda, yapıcı tarafından başlatılan [insertCommand] nesnesinin sorgusunun biçimsel parametrelerine değerler verilir. Bunu hatırlayalım:
insertCommand = New OdbcCommand("insert into ARTICLES(id, nom, prix, stockactuel, stockminimum) values (?,?,?,?,?)", connexion)
Sorgu için gerekli olan 5 değer, 7-11. satırlarda sağlanmaktadır.
- 13-19. satırlarda, sorgu yürütülür. Eğer başarılı olursa, sonuç döndürülür. Aksi takdirde, açık bir hata mesajı içeren genel bir istisna atılır
2.3.1.6. modifieArticle yöntemi
Açıklamalar:
- 1. satır - Yöntem, değiştirilecek öğeyi ODBC veri kaynağından alır. Bu işlemden etkilenen satır sayısını c.a.d olarak döndürür. 1 veya 0
- [ajouteArticle] yöntemine ait açıklamalar buraya aktarılabilir
2.3.1.7. supprimeArticle yöntemi
Açıklamalar:
- 1. satır - Yöntem, ODBC veri kaynağından silinecek ürün numarasını alır. Bu işlemden etkilenen satır sayısını c.a.d olarak döndürür. 1 veya 0
- [ajouteArticle] yöntemine ilişkin açıklamalar buraya da eklenebilir
2.3.1.8. getAllArticles yöntemi
Açıklamalar:
- 1. satır - Yöntem hiçbir parametre almaz. ODBC veri kaynağındaki tüm öğelerin listesini döndürür
- Tüm öğeleri talep eden [Select] sorgusu, [executeQuery] yöntemine gönderilir - 6. satır
- Elde edilen liste 8. satırda döndürülür
- 9-12. satırlarda, olası bir istisna işlenir
2.3.1.9. getArticleById yöntemi
Açıklamalar:
- 1. satır - Yöntem, istenen ürün numarasını parametre olarak alır. Bu ürün, ODBC kaynağında bulunursa o ürün, bulunmazsa [nothing] referansı döndürülür.
- Ürünü talep eden [Select] sorgusu 5-8. satırlarda başlatılır
- 12. satırda yürütülür – bir ürün listesi elde edilir
- Bu liste boşsa, 14. satırda [nothing] referansı döndürülür
- aksi takdirde, listedeki tek ürün 16. satırda döndürülür
- 17-20. satırlarda, olası bir istisna işlenir
2.3.1.10. clearAllArticles yöntemi
Açıklamalar:
- 1. satır - yöntem hiçbir parametre almaz ve hiçbir değer döndürmez
- 6. satır - tüm makalelerin silinmesi isteği yürütülür
- 7-10. satırlar: Olası bir istisna işlenir
2.3.1.11. changerStockArticle yöntemi
Açıklamalar:
- 1. satır - Yöntem, stok miktarı değiştirilecek ürün numarasını ve stok artışını (pozitif veya negatif) parametre olarak alır. c.a.d işlemi ile değiştirilen satır sayısını döndürür. 0 veya 1.
- 5-10. satırlar: [updateStockCommand] sorgusu başlatılır. SQL sorgusunun metnini hatırlayalım:
updateStockCommand = New OdbcCommand("update ARTICLES set stockactuel=stockactuel+? where id=? and (stockactuel+?)>=0", connexion)
Stokun, değiştirildikten sonra >=0 olarak kalması durumunda değiştirildiği dikkatinizi çekecektir.
- Ürünün stokunu güncelleme isteği 13. satırda yürütülür ve sonuç
- 14-18. satırlarda gösterilir; olası bir istisna durumuyla ilgilenilir
2.3.2. [dao] katmanının derlemesinin oluşturulması
[dao] katmanının bu yeni sürümüne ait Visual Studio projesi aşağıdaki yapıya sahiptir:

Proje, [webarticles-dao.dll] adlı bir DLL oluşturmak üzere yapılandırılmıştır:
![]() | ![]() |
2.3.3. [dao] katmanının NUnit testleri
2.3.3.1. 'den ODBC-Firebird kaynağının oluşturulması
Yeni [dao] katmanımızı test etmek için bir ODBC veri kaynağına ve dolayısıyla bir veritabanına ihtiyacımız var. SGBD Firebird'ü kullanıyoruz (bölüm 3.5). IBExpert (bölüm 3.6) ile aşağıdaki ürün veritabanını oluşturuyoruz:
![]() | ![]() |
Bu veritabanının yöneticisi, şifresi [masterkey] olan [SYSDBA] kullanıcısı olacaktır. Birkaç makale oluşturuyoruz:

Şimdi aşağıdaki ODBC Firebird kaynağını oluşturuyoruz (bkz. paragraf 3.7):
![]() |
Oluşturulan ODBC kaynağı aşağıdaki özelliklere sahiptir:
- ad: DSN: odbc-firebird-makaleler
- bağlantı kimliği: SYSDBA
- ilişkili şifre: masterkey
2.3.3.2. 'in NUnit test sınıfı
Başlangıçta oluşturulan [dao] katmanı için daha önce bir test sınıfı yazmıştık. Okuyucunun hatırlayacağı üzere, bu sınıf belirli bir sınıfı değil, [IArticlesDao] arayüzünü test ediyordu:
Imports System
Imports System.Collections
Imports NUnit.Framework
Imports istia.st.articles.dao
Imports System.Threading
Imports Spring.Objects.Factory.Xml
Imports System.IO
Namespace istia.st.articles.tests
<TestFixture()> _
Public Class NunitTestArticlesArrayList
' test edilecek nesne
Private articlesDao As IArticlesDao
<SetUp()> _
Public Sub init()
' Spring nesne oluşturucusunun bir örneği alınıyor
Dim factory As XmlObjectFactory = New XmlObjectFactory(New FileStream("spring-config.xml", FileMode.Open))
' articlesdao nesnesinin örneklenmesi isteniyor
articlesDao = CType(factory.GetObject("articlesdao"), IArticlesDao)
End Sub
....
Görüldüğü gibi, <Setup()> öznitelik yönteminde Spring'den, [IArticlesDao] türünde, yani arayüz türünde olan [articlesdao] adlı singleton'a ilişkin bir referans istenmektedir. [articlesdao] singleton'u, aşağıdaki [spring-config.xml] yapılandırma dosyası ile tanımlanmıştı:
<?xml version="1.0" encoding="iso-8859-1" ?>
<!DOCTYPE objects PUBLIC "-//SPRING//DTD OBJECT//EN"
"http://www.springframework.net/dtd/spring-objects.dtd">
<objects>
<object id="articlesdao" type="istia.st.articles.dao.ArticlesDaoArrayList, webarticles-dao"/>
</objects>
Başlangıçtaki test sınıfının, yeni katmanımız [dao]'i herhangi bir değişiklik veya yeniden derleme yapmadan test etmemize olanak sağladığını gösterelim.
- Yeni katmanımız [dao]’in Visual Studio klasöründe, [tests] (aşağıda sağda) klasörünü oluşturalım. Gerekirse, okuyucunun makalenin ilk bölümünde yer alan [dao] katmanının ilk sürümüne ait test projesini tekrar gözden geçirmesi önerilir.
![]() | ![]() |
- [tests] klasöründe, DLL'i [webarticles-dao.dll] ile değiştiriyoruz; bu,eski katman olan [dao]'ten gelen [webarticles-dao.dll] ve [webarticles-dao.dll]'i, yeni katman olan [dao]'ten gelen DLL ve [webarticles-dao.dll] ile değiştirin
- [spring-config.xml] yapılandırma dosyasını, yeni [ArticlesDaoPlainODBC] sınıfını örneklendirmek üzere değiştirelim:
Açıklamalar:
- 6. satırda, [articlesdao] nesnesi artık [ ArticlesDaoPlainODBC] sınıfının bir örneğiyle ilişkilendirilmiştir
- Bu sınıfın üç argümanlı bir oluşturucusu vardır:
- DSN kaynak adı - 8. satır
- veritabanına erişim için kullanılacak kimlik - satır 11
- bu kimliğe ait şifre - satır 14
Burada, daha önce oluşturduğumuz ODBC-Firebird kaynağındaki bilgileri kullanıyoruz.
2.3.3.3. Testler
Artık testlere hazırız. [Nunit-Gui] uygulaması yardımıyla, yukarıdaki [tests] klasöründen DLL ve [test-webarticles-dao.dll] dosyalarını yükleyip [testGetAllArticles] testini çalıştırıyoruz:

Yukarıdaki ekran görüntüsüne bakıldığında, test sınıfına başlangıçta verilen [NUnitTestArticlesDaoArrayList] adının biraz talihsiz olduğu söylenebilir. Bu durum kafa karışıklığına yol açabilir. Burada test edilen sınıf aslında [ArticlesDaoPlainODBC]'tir. Ekran görüntüsü, [ARTICLES] tablosuna yerleştirdiğimiz kayıtları doğru bir şekilde aldığımızı göstermektedir. Şimdi tüm testleri yapalım:

Soldaki pencerede, test edilen yöntemlerin listesi görülüyor. Her yöntemin adının önündeki noktanın rengi, yöntemin başarılı (yeşil) veya başarısız (kırmızı) olduğunu gösterir. Bu belgeyi ekranda görüntüleyen okuyucu, tüm testlerin başarılı olduğunu görebilir.
2.3.3.4. Sonuç
Az önce şunu gösterdik:
- çünkü NUnit test sınıfı bir sınıfa değil, bir arayüze referans veriyordu;
- çünkü arayüzün örneklendirileceği sınıfın tam adı kodda değil, bir yapılandırma dosyasında belirtilmişti;
- çünkü sınıfın örneklenmesi ve test koduna bir referans verilmesi Spring tarafından gerçekleştirildi;
Bu durumda, ilk [dao] katmanı için yazılan test kodu, aynı katmanın yeni bir uygulaması için de geçerli kalıyordu. Test sınıfının koduna erişmemize gerek kalmadı. Sadece derlenmiş halini kullandık; bu, ilk [dao] katmanının test edilmesi sırasında oluşturulan sürümdü. Yeni [dao] katmanını [webarticles] uygulamasına entegre etmemiz gerektiğinde de benzer sonuçlara varacağız.
2.3.4. Yeni [dao] katmanının [webarticles] uygulamasına entegrasyonu
2.3.4.1. Entegrasyon testleri
[webarticles] uygulamasının ilk sürümünün aşağıdaki [runtime] klasörüne dağıtıldığını hatırlayalım:
![]() | ![]() |
![]() |
Okuyucunun, [webarticles] uygulamasının dağıtım koşullarını ayrıntılı olarak açıklayan 2.2.4 numaralı paragrafı gerekirse tekrar gözden geçirmesi önerilir. [runtime] klasörünün içeriğinde aşağıdaki değişiklikleri yapıyoruz:
- [bin] klasöründe, eski katman [dao]'e ait DLL dosyası, yeni katman [dao]'e ait DLL dosyasıyla değiştirilmiştir
- [runtime]'te, [web.config] yapılandırma dosyası, [dao] katmanının yeni uygulama sınıfını dikkate alan bir dosyayla değiştirilir:
![]() |
![]() |
Yeni [web.config] yapılandırma dosyası şu şekildedir:
Açıklamalar:
- 14-24. satırlar, [articlesDao] tekil nesnesine yeni [ArticlesDaoPlainODBC] sınıfının bir örneğini atamaktadır. Tek değişiklik budur. Bu değişiklikle, yeni [dao] katmanının testleri sırasında daha önce karşılaşmıştık.
Testlere hazırız. [Cassini] web sunucusunu 2.2.4. paragrafında olduğu gibi yapılandırıyoruz. [Firebird] ürün tablosunu aşağıdaki değerlerle başlatıyoruz:

Cassini web sunucusunun yanı sıra SGBD ve [Firebird] sunucularının da çalışır durumda olduğundan emin olun. Bir tarayıcı kullanarak [http://localhost/webarticles/main.aspx] URL'sini çağırıyoruz:

![]() |
Şimdi [Firebird] veritabanındaki [ARTICLES] tablosunun içeriğini kontrol edelim:

[parapluie] ve [bottes] kalemleri satın alınmış ve stoklarından satın alınan miktar kadar düşülmüştür. [chapeau] kalemi, talep edilen miktar stoktaki miktarı aştığı için satın alınamamıştır. Okuyucuyu ek testler yapmaya davet ediyoruz.
2.3.4.2. Sonuç
Ne yaptık?
- Eski sürümün dağıtım sürümünü geri aldık;
- [dao] katmanındaki DLL'i yeni bir sürümle değiştirdik. [web] ve [domain] katmanlarındaki DLL'ler değişmeden kaldı;
- [web.config] yapılandırma dosyasını, [dao] katmanının yeni uygulama sınıfını dikkate alacak şekilde değiştirdik
Tüm bunlar, web uygulamasının gelişimine büyük kolaylık sağlayan temiz bir yapı oluşturmaktadır. Bu önemli özellikler, iki mimari seçim sayesinde elde edilmektedir:
- katmanlara arayüzler aracılığıyla erişim
- katmanların Spring aracılığıyla entegrasyonu ve yapılandırılması.
Şimdi [dao] katmanının yeni bir uygulamasını sunuyoruz.
2.4. [ArticlesDaoSqlServer] uygulama sınıfı
[dao] katmanının ikinci uygulaması, verilerin bir SQL Server veritabanında bulunduğunu varsayar. Microsoft, SQL Sunucusu'nun sınırlı bir sürümü olan ve MSDE olarak adlandırılan bir SGBD sunmaktadır. Bunu nasıl edinip kuracağınız, ekteki 3.12 numaralı paragrafta açıklanmaktadır.
2.4.1. Kod
[ArticlesDaoSqlServer] sınıfı, daha önce incelenen [ArticlesDaoPlainODBC] sınıfına çok benzemektedir. Bu nedenle, yalnızca önceki sürüme yapılan değişiklikleri belirteceğiz:
- gerekli sınıflar, [System.Data.Odbc] ad alanında değil, [System.Data.SqlClient] ad alanında yer almaktadır
- [OdbcConnection] türündeki bağlantı artık [SqlConnection] türündedir
- [OdbcCommand] nesneleri artık [SqlCommand] türündedir
- SQL ile parametreleştirilen sorguların sözdizimi değişir. Ekleme sorgusu şu şekilde olur:
insertCommand = New SqlCommand("insert into ARTICLES(id, nom, prix, stockactuel, stockminimum) values (@id,@nom,@prix,@sa,@sm)", connexion)
Oysa daha önce şöyleydi:
insertCommand = New OdbcCommand("insert into ARTICLES(id, nom, prix, stockactuel, stockminimum) values (?,?,?,?,?)", connexion)
- [ajouteArticle] yöntemi ise şu şekilde olur:
Public Function ajouteArticle(ByVal unArticle As Article) As Integer Implements IArticlesDao.ajouteArticle
' özel bölüm
SyncLock Me
' ekleme sorgusu hazırlanıyor
With insertCommand.Parameters
.Clear()
.Add(New SqlParameter("@id", unArticle.id))
.Add(New SqlParameter("@nom", unArticle.nom))
.Add(New SqlParameter("@prix", unArticle.prix))
.Add(New SqlParameter("@sa", unArticle.stockactuel))
.Add(New SqlParameter("@sm", unArticle.stockminimum))
End With
Try
'sorgu çalıştırılıyor
Return executeUpdate(insertCommand)
Catch ex As Exception
'sorgu hatası
Throw New Exception(String.Format("Erreur à l'ajout de l'article [{0}] : {1}", unArticle.ToString, ex.Message))
End Try
End SyncLock
End Function
- üretici de değiştirilmiştir:
Public Sub New(ByVal serveur As String, ByVal databaseName As String, ByVal uid As String, ByVal password As String)
' sunucu: ulaşılacak sunucunun adı SQL
' databaseName: ulaşılacak veritabanı adı
' uid: kullanıcı kimliği
' şifre: kullanıcının şifresi
': argüman olarak geçirilen veritabanı adı alınır
Me.databaseName = databaseName
': Bağlantı örneği oluşturulur
Dim connectString As String = String.Format("Data Source={0};Initial Catalog={1};UID={2};PASSWORD={3}", serveur, databaseName, uid, password)
connexion = New SqlConnection(connectString)
' sorgular hazırlanıyor SQL
insertCommand = New SqlCommand("insert into ARTICLES(id, nom, prix, stockactuel, stockminimum) values (@id,@nom,@prix,@sa,@sm)", connexion)
...
End Sub
Yapıcı artık dört parametre kabul ediyor:
' sunucu: SQL sunucusuna erişilecek örnek adı
' databaseName: ulaşılacak veritabanının adı
' uid: kullanıcı kimliği
' şifre: kullanıcının şifresi
[ArticlesDaoSqlServer] sınıfının tam kodu şöyledir:
Imports System
Imports System.Collections
Imports System.Data.SqlClient
Namespace istia.st.articles.dao
Public Class ArticlesDaoSqlServer
Implements istia.st.articles.dao.IArticlesDao
' özel alanlar
Private connexion As SqlConnection = Nothing
Private databaseName As String
Private insertCommand As SqlCommand
Private updatecommand As SqlCommand
Private deleteSomeCommand As SqlCommand
Private selectSomeCommand As SqlCommand
Private updateStockCommand As SqlCommand
Private deleteAllCommand As SqlCommand
Private selectAllCommand As SqlCommand
' oluşturucu
Public Sub New(ByVal serveur As String, ByVal databaseName As String, ByVal uid As String, ByVal password As String)
' sunucu: erişilecek SQL sunucusunun adı
' databaseName: ulaşılacak veritabanının adı
' uid: kullanıcı kimliği
' şifre: kullanıcının şifresi
': Argüman olarak geçirilen veritabanı adı alınır
Me.databaseName = databaseName
': Bağlantı örneği oluşturulur
Dim connectString As String = String.Format("Data Source={0};Initial Catalog={1};UID={2};PASSWORD={3}", serveur, databaseName, uid, password)
connexion = New SqlConnection(connectString)
' sorgular hazırlanır SQL
insertCommand = New SqlCommand("insert into ARTICLES(id, nom, prix, stockactuel, stockminimum) values (@id,@nom,@prix,@sa,@sm)", connexion)
updatecommand = New SqlCommand("update ARTICLES set nom=@nom, prix=@prix, stockactuel=@sa, stockminimum=@sm where id=@id", connexion)
deleteSomeCommand = New SqlCommand("delete from ARTICLES where id=@id", connexion)
selectSomeCommand = New SqlCommand("select id, nom, prix, stockactuel, stockminimum from ARTICLES where id=@id", connexion)
updateStockCommand = New SqlCommand("update ARTICLES set stockactuel=stockactuel+@mvt where id=@id and (stockactuel+@mvt)>=0", connexion)
selectAllCommand = New SqlCommand("select id, nom, prix, stockactuel, stockminimum from ARTICLES", connexion)
deleteAllCommand = New SqlCommand("delete from ARTICLES", connexion)
End Sub
Public Function ajouteArticle(ByVal unArticle As Article) As Integer Implements IArticlesDao.ajouteArticle
' özel bölüm
SyncLock Me
' ekleme sorgusu hazırlanıyor
With insertCommand.Parameters
.Clear()
.Add(New SqlParameter("@id", unArticle.id))
.Add(New SqlParameter("@nom", unArticle.nom))
.Add(New SqlParameter("@prix", unArticle.prix))
.Add(New SqlParameter("@sa", unArticle.stockactuel))
.Add(New SqlParameter("@sm", unArticle.stockminimum))
End With
Try
'sorgu çalıştırılıyor
Return executeUpdate(insertCommand)
Catch ex As Exception
'sorgu hatası
Throw New Exception(String.Format("Erreur à l'ajout de l'article [{0}] : {1}", unArticle.ToString, ex.Message))
End Try
End SyncLock
End Function
Public Function changerStockArticle(ByVal idArticle As Integer, ByVal mouvement As Integer) As Integer Implements IArticlesDao.changerStockArticle
' özel bölüm
SyncLock Me
' stok güncelleme sorgusu hazırlanıyor
With updateStockCommand.Parameters
.Clear()
.Add(New SqlParameter("@mvt", mouvement))
.Add(New SqlParameter("@id", idArticle))
End With
'işleniyor
Try
Return executeUpdate(updateStockCommand)
Catch ex As Exception
'istek hatası
Throw New Exception(String.Format("Erreur lors du changement de stock [idArticle={0}, mouvement={1}] : [{2}]", idArticle, mouvement, ex.Message))
End Try
End SyncLock
End Function
Public Sub clearAllArticles() Implements IArticlesDao.clearAllArticles
' özel bölüm
SyncLock Me
Try
'ekleme isteği yürütülüyor
executeUpdate(deleteAllCommand)
Catch ex As Exception
'sorgu hatası
Throw New Exception(String.Format("Erreur lors de la suppression des articles : {0}", ex.Message))
End Try
End SyncLock
End Sub
Public Function getAllArticles() As System.Collections.IList Implements IArticlesDao.getAllArticles
' özel bölüm
SyncLock Me
Try
'select sorgusu yürütülüyor
Dim articles As IList = executeQuery(selectAllCommand)
'liste döndürülüyor
Return articles
Catch ex As Exception
'sorgu hatası
Throw New Exception(String.Format("Erreur lors de l'obtention des articles [select id,nom,prix,stockactuel,stockminimum from articles]: {0}", ex.Message))
End Try
End SyncLock
End Function
Public Function getArticleById(ByVal idArticle As Integer) As Article Implements IArticlesDao.getArticleById
' özel bölüm
SyncLock Me
' SELECT sorgusu hazırlanıyor
With selectSomeCommand.Parameters
.Clear()
.Add(New SqlParameter("@id", idArticle))
End With
'sorgu yürütülüyor
Try
'sorgu yürütülüyor
Dim articles As IList = executeQuery(selectSomeCommand)
'makalenin bulunup bulunmadığını kontrol ediliyor
If articles.Count = 0 Then Return Nothing
'ürün döndürülüyor
Return CType(articles.Item(0), Article)
Catch ex As Exception
'sorgu hatası
Throw New Exception(String.Format("Erreur lors de la recherche de l'article [{0} : {1}", idArticle, ex.Message))
End Try
End SyncLock
End Function
Public Function modifieArticle(ByVal unArticle As Article) As Integer Implements IArticlesDao.modifieArticle
' özel bölüm
SyncLock Me
' güncelleme sorgusu hazırlanıyor
With updatecommand.Parameters
.Clear()
.Add(New SqlParameter("@nom", unArticle.nom))
.Add(New SqlParameter("@prix", unArticle.prix))
.Add(New SqlParameter("@sa", unArticle.stockactuel))
.Add(New SqlParameter("@sm", unArticle.stockminimum))
.Add(New SqlParameter("@id", unArticle.id))
End With
' yürütülüyor
Try
'ekleme isteği yürütülüyor
Return executeUpdate(updatecommand)
Catch ex As Exception
'sorgu hatası
Throw New Exception("Erreur lors de la modification de l'article [" + unArticle.ToString + "]", ex)
End Try
End SyncLock
End Function
Public Function supprimeArticle(ByVal idArticle As Integer) As Integer Implements IArticlesDao.supprimeArticle
' özel bölüm
SyncLock Me
' silme sorgusu hazırlanıyor
With deleteSomeCommand.Parameters
.Clear()
.Add(New SqlParameter("@id", idArticle))
End With
'işleniyor
Try
'silme sorgusu yürütülüyor
Return executeUpdate(deleteSomeCommand)
Catch ex As Exception
'istek hatası
Throw New Exception(String.Format("Erreur lors de la suppression de l'article [id={0}] : {1}", idArticle, ex.Message))
End Try
End SyncLock
End Function
Private Function executeQuery(ByVal query As SqlCommand) As IList
' bir sorgunun yürütülmesi SELECT
' sonuç tablosundaki tüm satırlara erişim sağlayan nesnenin tanımlanması
Dim myReader As SqlDataReader = Nothing
Try
'BDD'e bağlantı kuruluyor
connexion.Open()
'sorgu yürütülüyor
myReader = query.ExecuteReader()
'Sonrasında döndürülecek bir kayıt listesi tanımlanıyor
Dim articles As IList = New ArrayList
Dim unArticle As Article
While myReader.Read()
'okuyucunun değerleriyle bir ürün hazırlanır
unArticle = New Article
unArticle.id = myReader.GetInt32(0)
unArticle.nom = myReader.GetString(1)
unArticle.prix = myReader.GetDouble(2)
unArticle.stockactuel = myReader.GetInt32(3)
unArticle.stockminimum = myReader.GetInt32(4)
': Ürün listeye ekleniyor
articles.Add(unArticle)
End While
'sonuç döndürülüyor
Return articles
Finally
' kaynakların serbest bırakılması
If Not myReader Is Nothing And Not myReader.IsClosed Then myReader.Close()
If Not connexion Is Nothing Then connexion.Close()
End Try
End Function
Private Function executeUpdate(ByVal updateCommand As SqlCommand) As Integer
' güncelleme isteğinin yürütülmesi
Try
'BDD'e bağlantı kuruluyor
connexion.Open()
'sorgu yürütülüyor
Return updateCommand.ExecuteNonQuery()
Finally
' kaynakların serbest bırakılması
If Not connexion Is Nothing Then connexion.Close()
End Try
End Function
End Class
End Namespace
Okuyucunun, bu kodu daha önce yapılan [ArticlesDaoPlainODBC] sınıfı hakkındaki açıklamalar ışığında okuması önerilir.
2.4.2. [dao] katmanının derlemesinin oluşturulması
Yeni Visual Studio projesi aşağıdaki yapıya sahiptir:

Proje, [webarticles-dao.dll] adlı bir DLL oluşturmak üzere yapılandırılmıştır:
![]() | ![]() |
2.4.3. [dao] katmanının Nunit testleri
2.4.3.1. 'da SQL Server veri kaynağı oluşturma
Yeni katmanımızı [dao] test etmek için bir veri kaynağına SQL Server ihtiyacımız var ve dolayısıyla SGBD SQL Server'a da ihtiyacımız var. Aslında SGBD MSDE (MicroSoft Veri Motoru) (paragraf 3.12) kullanacağız; bu, SQL Sunucusunun, yalnızca kabul edilen eşzamanlı kullanıcı sayısı ile sınırlandırılmış bir sürümüdür. [EMS MS SQL Manager] (paragraf 3.14) ile, [portable1_tahe\msde140405] adlı bir MSDE örneğinde aşağıdaki makale tabanını oluşturuyoruz:
![]() | ![]() |

Tablonun sahibi, şifresi [admarticles] olan [mdparticles] kullanıcısıdır. [ARTICLES] tablosunu oluşturan Transact-SQL komutu şöyledir:
CREATE TABLE [ARTICLES] (
[id] int NOT NULL,
[nom] varchar(20) COLLATE French_CI_AS NOT NULL,
[prix] float(53) NOT NULL,
[stockactuel] int NOT NULL,
[stockminimum] int NOT NULL,
CONSTRAINT [ARTICLES_uq] UNIQUE ([nom]),
PRIMARY KEY ([id]),
CONSTRAINT [ARTICLES_ck_id] CHECK ([id] > 0),
CONSTRAINT [ARTICLES_ck_nom] CHECK ([nom] <> ''),
CONSTRAINT [ARTICLES_ck_prix] CHECK ([prix] >= 0),
CONSTRAINT [ARTICLES_ck_stockactuel] CHECK ([stockactuel] >= 0),
CONSTRAINT [ARTICLES_ck_stockminimum] CHECK ([stockminimum] >= 0)
)
ON [PRIMARY]
GO
Birkaç makale oluşturuyoruz:

2.4.3.2. NUnit test sınıfı
[ArticlesDaoSqlServer] uygulama sınıfının NUnit test sınıfı, [ArticlesDaoPlainODBC] sınıfınınkiyle aynıdır (bkz. 2.3.3.2. paragraf). Sınıfın NUnit testini hazırlamak için benzer bir yaklaşım izliyoruz:
- [dao-sqlserver] projesinin Visual Studio klasöründe, [dao-odbc] projesindeki (solda) [tests] klasörünü kopyalayarak [tests] klasörünü (sağda) oluşturuyoruz:
![]() | ![]() |
- [dao-sqlserver] projesindeki [tests] klasörüne, DLL ve [webarticles-dao.dll] dosyalarını, [dao-sqlserver] projesinin oluşturulması sırasında elde edilen DLL ve [webarticles-dao.dll] dosyalarıyla değiştiriyoruz
- Yeni [ArticlesDaoSqlServer] sınıfını oluşturmak için [spring-config.xml] yapılandırma dosyasını değiştiriyoruz:
Açıklamalar:
- 7. satırda, [articlesdao] nesnesi artık [ ArticlesDaoSqlServeur] sınıfının bir örneğiyle ilişkilendirilmiştir
- bu sınıfın dört argümanlı bir oluşturucusu vardır:
- kullanılan MSDE örneğinin adı - 9. satır
- veritabanının adı - satır 12
- veritabanına erişim için kullanılacak kimlik - satır 15
- bu kimliğe ait şifre - satır 18
Burada, daha önce oluşturduğumuz MSDE kaynağındaki bilgileri kullanıyoruz.
2.4.3.3. Testler
Testlere hazırız. [Nunit-Gui] uygulamasını kullanarak, yukarıdaki [tests] klasöründen DLL ve [test-webarticles-dao.dll] dosyalarını yükleyip [testGetAllArticles] testini çalıştırıyoruz:

Test sınıfına başlangıçta verilen ve bu sınıftan türetilen DLL ile [tests-webarticles-dao.dll]'i kullandığımız için korunan [NUnitTestArticlesDaoArrayList] adı olmasına rağmen, burada test edilen sınıf aslında [ArticlesDaoSqlserver]'tir. Ekran görüntüsü, [ARTICLES] tablosuna yerleştirdiğimiz kayıtları doğru bir şekilde aldığımızı göstermektedir. Şimdi tüm testleri yapalım:

Soldaki pencerede, test edilen yöntemlerin listesi görülüyor. Her yöntemin adının önündeki noktanın rengi, yöntemin başarılı (yeşil) veya başarısız (kırmızı) olduğunu gösterir. Bu belgeyi ekranda görüntüleyen okuyucu, tüm testlerin başarılı olduğunu görebilir.
2.4.4. Yeni [dao] katmanının [webarticles] uygulamasına entegrasyonu
2.3.4. paragrafında açıklanan prosedürü izliyoruz. [runtime] klasörünün içeriğinde aşağıdaki değişiklikleri yapıyoruz:
- [bin] klasöründe,eski katman olan [dao]'teki DLL dosyası, [ArticlesDaoSqlServer] sınıfı tarafından uygulanan yeni katman [dao]'teki DLL dosyasıyla değiştirilir
- [runtime]'te, [web.config] yapılandırma dosyası, yeni uygulama sınıfını dikkate alan bir dosyayla değiştirilir:
Açıklamalar:
- 15-33. satırlar, [articlesDao] tekil nesnesine yeni [ArticlesDaoSqlServer] sınıfının bir örneğini atamaktadır. Yapılan tek değişiklik budur. Bu değişiklikle, yeni [dao] katmanının testleri sırasında daha önce karşılaşmıştık
Testlere hazırız. [Cassini] web sunucusunun yapılandırmasını eskisiyle aynı tutuyoruz. [MSDE] makale tablosunu aşağıdaki değerlerle başlatıyoruz:

Cassini web sunucusunun yanı sıra SGBD ve MSDE (burada portable1_tahe\msde140405 örneği) sunucularının çalışır durumda olduğundan emin olun. Bir tarayıcı kullanarak URL ve [http://localhost/webarticles/main.aspx] adreslerini çağırıyoruz:

![]() |
Şimdi [MSDE] veritabanındaki [ARTICLES] tablosunun içeriğini kontrol edelim:

[ballon foot] ve [raquette tennis] numaralı ürünler satın alınmış ve stoklarından satın alınan miktar kadar düşülmüştür. [rollers] numaralı ürün, talep edilen miktar stoktaki miktarı aştığı için satın alınamamıştır. Okuyucuyu ek testler yapmaya davet ediyoruz.
2.4.5. [ArticlesDaoOleDb] uygulama sınıfı
2.4.5.1. OleDb veri kaynakları
[dao] katmanının üçüncü uygulaması, verilerin bir OleDb sürücüsü aracılığıyla erişilebilen bir veritabanında olduğunu varsayar. OleDb kaynaklarının çalışma prensibi, ODBC kaynaklarınınkine benzerdir. Bir OleDb kaynağını kullanan bir program, bunu tüm OleDb kaynakları için ortak olan standart bir arayüz üzerinden gerçekleştirir. OleDb kaynağını değiştirmek, OleDb sürücüsünü değiştirmekle aynı anlama gelir. Kodta herhangi bir değişiklik yapılmaz.
Visual Studio sayesinde bilgisayarınızda bulunan OleDb sürücülerini öğrenebilirsiniz:
- [Affichage/Explorateur de serveurs] ile sunucu gezginiyi görüntüleyin:

- Yeni bir bağlantı eklemek için, [Connexion de données] üzerine sağ tıklayın ve [Ajouter une connexion] seçeneğini seçin. Ardından, bağlantının özelliklerini tanımlayabileceğiniz bir sihirbaz açılır:

- [Fournisseur] paneli, mevcut OLEDB sürücülerinin listesini gösterir. Yeni katman için [dao]'i kullanacağız; bu, [Microsoft Jet 4.0 OLE DB Provider] veritabanlarına erişim sağlayan bir sürücüdür.
- Şu anda Visual Studio'dan çıkıp, aşağıdaki tek tabloyu içeren ACCESS [articles.mdb] veritabanını oluşturmak için adresine gidelim:

- Tablonun yapısı şu şekildedir:
sayısal - tamsayı - birincil anahtar | |
metin - 20 karakter - | |
sayısal - çift hassasiyetli gerçek sayı | |
sayısal - tamsayı | |
sayısal - tamsayı |
- Visual Studio'ya geri dönelim ve daha önce açıklandığı gibi yeni bir bağlantı oluşturalım:

- [Microsoft Jet 4.0] sürücüsünü seçip [Connexion] paneline geçelim:

- [1] düğmesiyle, az önce oluşturulan ACCESS veritabanını seçin ve ardından [Terminer] düğmesiyle bağlantı tanımlamasını tamamlayın. Oluşturulan bağlantı artık kullanılabilir bağlantılar listesinde görünür:

- [ARTICLES] tablosuna çift tıklayarak içeriğine erişebiliriz:

- Böylece tabloda satır ekleyebilir, değiştirebilir veya silebilirsiniz.
- Sunucu gezgininde, özellikler sayfasına erişmek için yeni bağlantıyı seçin:

- Bağlantı dizesini bilmek faydalıdır. Bu, veritabanına bağlanmak için bize yardımcı olacaktır:
Provider=Microsoft.Jet.OLEDB.4.0;User ID=Admin;Data Source=D:\data\serge\databases\access\articles\articles.mdb;Mode=Share Deny None;Extended Properties="";Jet OLEDB:System database="";Jet OLEDB:Registry Path="";Jet OLEDB:Engine Type=5;Jet OLEDB:Database Locking Mode=1;Jet OLEDB:Global Partial Bulk Ops=2;Jet OLEDB:Global Bulk Transactions=1;Jet OLEDB:Create System Database=False;Jet OLEDB:Encrypt Database=False;Jet OLEDB:Don't Copy Locale on Compact=False;Jet OLEDB:Compact Without Replica Repair=False;Jet OLEDB:SFP=False
- Bu dizeden yalnızca aşağıdaki öğeleri alacağız:
2.4.5.2. [ArticlesDaoOleDb] sınıfının kodu
[ArticlesDaoOleDb] sınıfı, daha önce incelediğimiz [ArticlesDaoPlainODBC] sınıfına çok benzemektedir. Bu nedenle, önceki sürüme göre yapılan değişiklikleri belirtmekle yetineceğiz:
- Gerekli sınıflar, [System.Data.Odbc] ad alanında değil, [System.Data.OleDb] ad alanında yer almaktadır
- [OdbcConnection] türündeki bağlantı artık [OleDbConnection] türündedir
- [OdbcCommand] nesneleri artık [OleDbCommand] türündedir
Sınıfın oluşturucusu, tek parametre olarak veritabanına bağlantı dizesini kabul eder:
' oluşturucu
Public Sub New(ByVal connectString As String)
' connectString: OleDb kaynağına bağlantı dizesi
'bağlantı örneği oluşturuluyor
connexion = New OleDbConnection(connectString)
' istekler hazırlanıyor SQL
...
End Sub
[ArticlesDaoOleDb] sınıfının tam kodu şöyledir:
Imports System
Imports System.Collections
Imports System.Data.OleDb
Namespace istia.st.articles.dao
Public Class ArticlesDaoOleDb
Implements istia.st.articles.dao.IArticlesDao
' özel alanlar
Private connexion As OleDbConnection = Nothing
Private insertCommand As OleDbCommand
Private updatecommand As OleDbCommand
Private deleteSomeCommand As OleDbCommand
Private selectSomeCommand As OleDbCommand
Private updateStockCommand As OleDbCommand
Private deleteAllCommand As OleDbCommand
Private selectAllCommand As OleDbCommand
' oluşturucu
Public Sub New(ByVal connectString As String)
' connectString : kaynağa bağlantı dizesi OleDb
'bağlantı örneği oluşturulur
connexion = New OleDbConnection(connectString)
' istekler hazırlanıyor SQL
insertCommand = New OleDbCommand("insert into ARTICLES(id, nom, prix, stockactuel, stockminimum) values (?,?,?,?,?)", connexion)
updatecommand = New OleDbCommand("update ARTICLES set nom=?, prix=?, stockactuel=?, stockminimum=? where id=?", connexion)
deleteSomeCommand = New OleDbCommand("delete from ARTICLES where id=?", connexion)
selectSomeCommand = New OleDbCommand("select id, nom, prix, stockactuel, stockminimum from ARTICLES where id=?", connexion)
updateStockCommand = New OleDbCommand("update ARTICLES set stockactuel=stockactuel+? where id=? and (stockactuel+?)>=0", connexion)
selectAllCommand = New OleDbCommand("select id, nom, prix, stockactuel, stockminimum from ARTICLES", connexion)
deleteAllCommand = New OleDbCommand("delete from ARTICLES", connexion)
End Sub
Public Function ajouteArticle(ByVal unArticle As Article) As Integer Implements IArticlesDao.ajouteArticle
' özel bölüm
SyncLock Me
' ekleme isteği hazırlanıyor
With insertCommand.Parameters
.Clear()
.Add(New OleDbParameter("id", unArticle.id))
.Add(New OleDbParameter("nom", unArticle.nom))
.Add(New OleDbParameter("prix", unArticle.prix))
.Add(New OleDbParameter("stockactuel", unArticle.stockactuel))
.Add(New OleDbParameter("stockminimum", unArticle.stockminimum))
End With
Try
'sorgu yürütülüyor
Return executeUpdate(insertCommand)
Catch ex As Exception
'sorgu hatası
Throw New Exception(String.Format("Erreur à l'ajout de l'article [{0}] : {1}", unArticle.ToString, ex.Message))
End Try
End SyncLock
End Function
Public Function changerStockArticle(ByVal idArticle As Integer, ByVal mouvement As Integer) As Integer Implements IArticlesDao.changerStockArticle
' özel bölüm
SyncLock Me
' stok güncelleme sorgusu hazırlanıyor
With updateStockCommand.Parameters
.Clear()
.Add(New OleDbParameter("mvt1", mouvement))
.Add(New OleDbParameter("id", idArticle))
.Add(New OleDbParameter("mvt2", mouvement))
End With
'işleniyor
Try
Return executeUpdate(updateStockCommand)
Catch ex As Exception
'istek hatası
Throw New Exception(String.Format("Erreur lors du changement de stock [idArticle={0}, mouvement={1}] : [{2}]", idArticle, mouvement, ex.Message))
End Try
End SyncLock
End Function
Public Sub clearAllArticles() Implements IArticlesDao.clearAllArticles
' özel bölüm
SyncLock Me
Try
'ekleme isteği yürütülüyor
executeUpdate(deleteAllCommand)
Catch ex As Exception
'sorgu hatası
Throw New Exception(String.Format("Erreur lors de la suppression des articles : {0}", ex.Message))
End Try
End SyncLock
End Sub
Public Function getAllArticles() As System.Collections.IList Implements IArticlesDao.getAllArticles
' özel bölüm
SyncLock Me
Try
'select sorgusu yürütülüyor
Dim articles As IList = executeQuery(selectAllCommand)
'liste döndürülüyor
Return articles
Catch ex As Exception
'sorgu hatası
Throw New Exception(String.Format("Erreur lors de l'obtention des articles [select id,nom,prix,stockactuel,stockminimum from articles]: {0}", ex.Message))
End Try
End SyncLock
End Function
Public Function getArticleById(ByVal idArticle As Integer) As Article Implements IArticlesDao.getArticleById
' özel bölüm
SyncLock Me
' SELECT sorgusu hazırlanıyor
With selectSomeCommand.Parameters
.Clear()
.Add(New OleDbParameter("id", idArticle))
End With
'sorgu yürütülüyor
Try
'sorgu yürütülüyor
Dim articles As IList = executeQuery(selectSomeCommand)
'makalenin bulunup bulunmadığını kontrol ediliyor
If articles.Count = 0 Then Return Nothing
'ürün döndürülüyor
Return CType(articles.Item(0), Article)
Catch ex As Exception
'sorgu hatası
Throw New Exception(String.Format("Erreur lors de la recherche de l'article [{0} : {1}", idArticle, ex.Message))
End Try
End SyncLock
End Function
Public Function modifieArticle(ByVal unArticle As Article) As Integer Implements IArticlesDao.modifieArticle
' özel bölüm
SyncLock Me
' güncelleme sorgusu hazırlanıyor
With updatecommand.Parameters
.Clear()
.Add(New OleDbParameter("nom", unArticle.nom))
.Add(New OleDbParameter("prix", unArticle.prix))
.Add(New OleDbParameter("stockactuel", unArticle.stockactuel))
.Add(New OleDbParameter("stockminimum", unArticle.stockactuel))
.Add(New OleDbParameter("id", unArticle.id))
End With
' yürütülüyor
Try
'ekleme isteği yürütülüyor
Return executeUpdate(updatecommand)
Catch ex As Exception
'sorgu hatası
Throw New Exception("Erreur lors de la modification de l'article [" + unArticle.ToString + "]", ex)
End Try
End SyncLock
End Function
Public Function supprimeArticle(ByVal idArticle As Integer) As Integer Implements IArticlesDao.supprimeArticle
' özel bölüm
SyncLock Me
' silme sorgusu hazırlanıyor
With deleteSomeCommand.Parameters
.Clear()
.Add(New OleDbParameter("id", idArticle))
End With
'yürütülüyor
Try
'silme sorgusu yürütülüyor
Return executeUpdate(deleteSomeCommand)
Catch ex As Exception
'istek hatası
Throw New Exception(String.Format("Erreur lors de la suppression de l'article [id={0}] : {1}", idArticle, ex.Message))
End Try
End SyncLock
End Function
Private Function executeQuery(ByVal query As OleDbCommand) As IList
' bir sorgunun yürütülmesi SELECT
' sonuç tablosundaki tüm satırlara erişim sağlayan nesnenin tanımlanması
Dim myReader As OleDbDataReader = Nothing
Try
'BDD'e bir bağlantı oluşturuluyor
connexion.Open()
'sorgu yürütülüyor
myReader = query.ExecuteReader()
'Daha sonra döndürülmek üzere bir kayıt listesi tanımlanıyor
Dim articles As IList = New ArrayList
Dim unArticle As Article
While myReader.Read()
'okuyucunun değerleriyle bir ürün hazırlanır
unArticle = New Article
unArticle.id = myReader.GetInt32(0)
unArticle.nom = myReader.GetString(1)
unArticle.prix = myReader.GetDouble(2)
unArticle.stockactuel = myReader.GetInt32(3)
unArticle.stockminimum = myReader.GetInt32(4)
': Ürünü listeye ekleniyor
articles.Add(unArticle)
End While
'sonuç döndürülüyor
Return articles
Finally
' kaynakların serbest bırakılması
If Not myReader Is Nothing And Not myReader.IsClosed Then myReader.Close()
If Not connexion Is Nothing Then connexion.Close()
End Try
End Function
Private Function executeUpdate(ByVal sqlCommand As OleDbCommand) As Integer
' güncelleme isteğinin yürütülmesi
Try
'BDD'e bağlantı kuruluyor
connexion.Open()
'sorgu yürütülüyor
Return sqlCommand.ExecuteNonQuery()
Finally
' kaynakların serbest bırakılması
If Not connexion Is Nothing Then connexion.Close()
End Try
End Function
End Class
End Namespace
Okuyucunun, bu kodu daha önce yapılan [ArticlesDaoPlainODBC] sınıfı hakkındaki açıklamalar ışığında okuması önerilir.
2.4.5.3. [dao] katmanının derlemesinin oluşturulması
Yeni Visual Studio projesi aşağıdaki yapıya sahiptir:

Proje, [webarticles-dao.dll] adlı bir DLL oluşturmak üzere yapılandırılmıştır:
![]() | ![]() |
2.4.5.4. [dao] katmanının Nunit testleri
2.4.5.4.1. NUnit test sınıfı
[ArticlesDaoOleDb] uygulama sınıfının Nunit test sınıfı, [ArticlesDaoPlainODBC] sınıfınkiyle aynıdır (bkz. 2.3.3.2. paragraf). Sınıfın Nunit testini hazırlamak için benzer bir yaklaşım izliyoruz:
- [dao-oledb] projesinin Visual Studio klasöründe, [dao-odbc] projesindeki (solda) [tests] klasörünü kopyalayarak [tests] klasörünü (sağda) oluşturuyoruz:
![]() | ![]() |
- [dao-oledb] projesinin [tests] klasöründe, DLL ve [webarticles-dao.dll] klasörlerini DLL ve [webarticles-dao.dll] ile değiştiriyoruz; bu dosya, [dao-oledb] projesinin oluşturulmasından kaynaklanmaktadır
- yeni [ArticlesDaoOleDb] sınıfını örneklendirmek için [spring-config.xml] yapılandırma dosyasını değiştiriyoruz:
Açıklamalar:
- 7. satırda, [articlesdao] nesnesi artık [ ArticlesDaoOleDb] sınıfının bir örneğiyle ilişkilendirilmiştir
- bu sınıfın tek argümanlı bir oluşturucusu vardır: OleDb veritabanına bağlantı dizesi ACCESS - 9. satır
2.4.5.4.2. Tests
Testlere hazırız. [Nunit-Gui] uygulamasını kullanarak, yukarıdaki [tests] klasöründen DLL [test-webarticles-dao.dll] dosyasını yükleyip [testGetAllArticles] testini çalıştırıyoruz:

Test sınıfına başlangıçta [NUnitTestArticlesDaoArrayList] adı verilmiş olmasına rağmen, burada test edilen sınıf aslında [ArticlesDaoOleDb]'tir. Ekran görüntüsü, [ARTICLES] tablosuna yerleştirdiğimiz kayıtları doğru bir şekilde aldığımızı göstermektedir. Şimdi tüm testleri yapalım:

Bu belgeyi ekranda görüntüleyen okuyucu, tüm testlerin başarılı olduğunu (yeşil renk) görebilecektir.
2.4.5.5. Yeni [dao] katmanının [webarticles] uygulamasına entegrasyonu
2.3.4. paragrafında açıklanan adımları takip ediyoruz. [runtime] klasörünün içeriğinde aşağıdaki değişiklikleri yapıyoruz:
- [bin] klasöründe,eski katman olan [dao]'teki DLL dosyası, [ArticlesDaoOleDb] sınıfı tarafından uygulanan yeni katman [dao]'teki DLL dosyasıyla değiştirilir
- [runtime]'te, [web.config] yapılandırma dosyası, yeni uygulama sınıfını dikkate alan bir dosyayla değiştirilir:
Açıklamalar:
- 14-18. satırlar, [articlesDao] tekil nesnesine yeni [ArticlesDaoOleDb] sınıfının bir örneğini atar. Yapılan tek değişiklik budur.
[Cassini] web sunucusunun yapılandırmasını eskisiyle aynı tutuyoruz. Makale tablosunu aşağıdaki değerlerle başlatıyoruz:

Makale tabanının Visual Studio veya ACCESS gibi bir program tarafından kullanılmadığından emin olun. Bir tarayıcı kullanarak URL ve [http://localhost/webarticles/main.aspx] adreslerini çağırıyoruz:

![]() |
Şimdi [ARTICLES] tablosunun içeriğini ACCESS ile kontrol edelim:

[pantalon] ve [jupe] kalemleri satın alınmış ve stoklarından satın alınan miktar kadar düşülmüştür. [manteau] kalemi, talep edilen miktar stoktaki miktarı aştığı için satın alınamamıştır. Okuyucuyu ek testler yapmaya davet ediyoruz.
2.5. [ArticlesDaoFirebirdProvider] uygulama sınıfı
2.5.1. Firebird-net-provider erişim sağlayıcısı
Daha önce, ODBC sürücüsü aracılığıyla kullandığımız [Firebird] veri kaynağını kullanmıştık. ODBC sürücüleri, bunları kullanan kodlara yüksek yeniden kullanılabilirlik sağlasa da, hedef SGBD için özel olarak yazılmış sürücülere kıyasla daha düşük performans gösterir. SGBD ve [Firebird], Firebird [http://firebird.sourceforge.net/] sitesinden indirilebilen özel sınıf kütüphanesi aracılığıyla kullanılabilir. İndirme sayfasında şu bağlantılar yer almaktadır (Nisan 2005):
![]()
[firebird-net-provider] bağlantısı, Firebird'e erişim sağlayan .NET sınıflarını indirmek için kullanılacak bağlantıdır. Paketin kurulumu, aşağıdakine benzer bir klasör oluşturur:

Burada iki öğe dikkatimizi çekiyor:
- [FirebirdSql.Data.Firebird.dll]: SGBD Firebird'e erişim sağlayan .NET sınıflarını içeren derleme
- [FirebirdNETProviderSDK.chm]: Bu sınıflarla ilgili belgeler
Daha sonra, bir Visual Studio projesinin bu sınıfları kullanabilmesi için iki şey yapacağız:
- [FirebirdSql.Data.Firebird.dll] derlemesini projenin [bin] klasörüne yerleştireceğiz
- aynı assembly'yi projenin referanslarına ekleyeceğiz
2.5.2. [ArticlesDaoFirebirdProvider] sınıfının kodu
[ArticlesDaoFirebirdProvider] sınıfı, daha önce incelediğimiz [ArticlesDaoSqlServer] sınıfına çok benzemektedir. Bu nedenle, bu sürüme göre yapılan değişiklikleri belirtmekle yetineceğiz:
- Gerekli sınıflar, [System.Data.SqlClient] ad alanında değil, [FirebirdSql.Data.Firebird] ad alanında yer almaktadır
- [SqlConnection] türündeki bağlantı artık [FbConnection] türündedir
- [SqlCommand] nesneleri artık [FbCommand] türündedir
- [SqlParameter] nesneleri artık [FbParameter] türündedir
Sınıf oluşturucu, veritabanına bağlantı dizesini oluşturmak için dört parametre kabul eder:
' oluşturucu
Public Sub New(ByVal serveur As String, ByVal databaseName As String, ByVal uid As String, ByVal password As String)
' sunucu: SGBD'in ana bilgisayar adı
' databaseName: veritabanına erişim yolu
' uid: Oturum açan kullanıcının kimliği
' password: şifresi
...
End Sub
[ArticlesDaoFirebirdProvider] sınıfının tam kodu şöyledir:
Imports System
Imports System.Collections
Imports FirebirdSql.Data.Firebird
Namespace istia.st.articles.dao
Public Class ArticlesDaoFirebirdProvider
Implements istia.st.articles.dao.IArticlesDao
' özel alanlar
Private connexion As FbConnection = Nothing
Private databasePath As String
Private insertCommand As FbCommand
Private updatecommand As FbCommand
Private deleteSomeCommand As FbCommand
Private selectSomeCommand As FbCommand
Private updateStockCommand As FbCommand
Private deleteAllCommand As FbCommand
Private selectAllCommand As FbCommand
' üretici
Public Sub New(ByVal serveur As String, ByVal databasePath As String, ByVal uid As String, ByVal password As String)
' sunucu: SGBD Firebird'ün ana bilgisayar adı
' databaseName: kullanılacak veritabanının yolu
' uid: veritabanına bağlanan kullanıcının kimliği
' password: kullanıcının şifresi
': Argüman olarak geçirilen veritabanının adı alınır
Me.databasePath = databasePath
': Bağlantı örneği oluşturulur
Dim connectString As String = String.Format("DataSource={0};Database={1};User={2};Password={3}", serveur, databasePath, uid, password)
connexion = New FbConnection(connectString)
' sorgular hazırlanır SQL
insertCommand = New FbCommand("insert into ARTICLES(id, nom, prix, stockactuel, stockminimum) values (@id,@nom,@prix,@sa,@sm)", connexion)
updatecommand = New FbCommand("update ARTICLES set nom=@nom, prix=@prix, stockactuel=@sa, stockminimum=@sm where id=@id", connexion)
deleteSomeCommand = New FbCommand("delete from ARTICLES where id=@id", connexion)
selectSomeCommand = New FbCommand("select id, nom, prix, stockactuel, stockminimum from ARTICLES where id=@id", connexion)
updateStockCommand = New FbCommand("update ARTICLES set stockactuel=stockactuel+@mvt where id=@id and (stockactuel+@mvt)>=0", connexion)
selectAllCommand = New FbCommand("select id, nom, prix, stockactuel, stockminimum from ARTICLES", connexion)
deleteAllCommand = New FbCommand("delete from ARTICLES", connexion)
End Sub
Public Function ajouteArticle(ByVal unArticle As Article) As Integer Implements IArticlesDao.ajouteArticle
' özel bölüm
SyncLock Me
' ekleme sorgusu hazırlanıyor
With insertCommand.Parameters
.Clear()
.Add(New FbParameter("@id", unArticle.id))
.Add(New FbParameter("@nom", unArticle.nom))
.Add(New FbParameter("@prix", unArticle.prix))
.Add(New FbParameter("@sa", unArticle.stockactuel))
.Add(New FbParameter("@sm", unArticle.stockminimum))
End With
Try
'sorgu yürütülüyor
Return executeUpdate(insertCommand)
Catch ex As Exception
'sorgu hatası
Throw New Exception(String.Format("Erreur à l'ajout de l'article [{0}] : {1}", unArticle.ToString, ex.Message))
End Try
End SyncLock
End Function
Public Function changerStockArticle(ByVal idArticle As Integer, ByVal mouvement As Integer) As Integer Implements IArticlesDao.changerStockArticle
' özel bölüm
SyncLock Me
' stok güncelleme sorgusu hazırlanıyor
With updateStockCommand.Parameters
.Clear()
.Add(New FbParameter("@mvt", mouvement))
.Add(New FbParameter("@id", idArticle))
End With
'işleniyor
Try
Return executeUpdate(updateStockCommand)
Catch ex As Exception
'istek hatası
Throw New Exception(String.Format("Erreur lors du changement de stock [idArticle={0}, mouvement={1}] : [{2}]", idArticle, mouvement, ex.Message))
End Try
End SyncLock
End Function
Public Sub clearAllArticles() Implements IArticlesDao.clearAllArticles
' özel bölüm
SyncLock Me
Try
'ekleme isteği yürütülüyor
executeUpdate(deleteAllCommand)
Catch ex As Exception
'sorgu hatası
Throw New Exception(String.Format("Erreur lors de la suppression des articles : {0}", ex.Message))
End Try
End SyncLock
End Sub
Public Function getAllArticles() As System.Collections.IList Implements IArticlesDao.getAllArticles
' özel bölüm
SyncLock Me
Try
'select sorgusu yürütülüyor
Dim articles As IList = executeQuery(selectAllCommand)
'liste döndürülüyor
Return articles
Catch ex As Exception
'sorgu hatası
Throw New Exception(String.Format("Erreur lors de l'obtention des articles [select id,nom,prix,stockactuel,stockminimum from articles]: {0}", ex.Message))
End Try
End SyncLock
End Function
Public Function getArticleById(ByVal idArticle As Integer) As Article Implements IArticlesDao.getArticleById
' özel bölüm
SyncLock Me
' select sorgusu hazırlanıyor
With selectSomeCommand.Parameters
.Clear()
.Add(New FbParameter("@id", idArticle))
End With
'sorgu yürütülüyor
Try
'sorgu yürütülüyor
Dim articles As IList = executeQuery(selectSomeCommand)
'makalenin bulunup bulunmadığını kontrol ediliyor
If articles.Count = 0 Then Return Nothing
'ürün döndürülüyor
Return CType(articles.Item(0), Article)
Catch ex As Exception
'sorgu hatası
Throw New Exception(String.Format("Erreur lors de la recherche de l'article [{0} : {1}", idArticle, ex.Message))
End Try
End SyncLock
End Function
Public Function modifieArticle(ByVal unArticle As Article) As Integer Implements IArticlesDao.modifieArticle
' özel bölüm
SyncLock Me
' güncelleme sorgusu hazırlanıyor
With updatecommand.Parameters
.Clear()
.Add(New FbParameter("@nom", unArticle.nom))
.Add(New FbParameter("@prix", unArticle.prix))
.Add(New FbParameter("@sa", unArticle.stockactuel))
.Add(New FbParameter("@sm", unArticle.stockminimum))
.Add(New FbParameter("@id", unArticle.id))
End With
' yürütülüyor
Try
'ekleme isteği yürütülüyor
Return executeUpdate(updatecommand)
Catch ex As Exception
'sorgu hatası
Throw New Exception("Erreur lors de la modification de l'article [" + unArticle.ToString + "]", ex)
End Try
End SyncLock
End Function
Public Function supprimeArticle(ByVal idArticle As Integer) As Integer Implements IArticlesDao.supprimeArticle
' özel bölüm
SyncLock Me
' silme sorgusu hazırlanıyor
With deleteSomeCommand.Parameters
.Clear()
.Add(New FbParameter("@id", idArticle))
End With
'sorgu yürütülüyor
Try
'silme sorgusu yürütülüyor
Return executeUpdate(deleteSomeCommand)
Catch ex As Exception
'istek hatası
Throw New Exception(String.Format("Erreur lors de la suppression de l'article [id={0}] : {1}", idArticle, ex.Message))
End Try
End SyncLock
End Function
Private Function executeQuery(ByVal query As FbCommand) As IList
' bir sorgunun yürütülmesi SELECT
' sonuç tablosundaki tüm satırlara erişim sağlayan nesnenin tanımlanması
Dim myReader As FbDataReader = Nothing
Try
'BDD'e bağlantı kuruluyor
connexion.Open()
'sorgu çalıştırılıyor
myReader = query.ExecuteReader()
'Daha sonra döndürülecek bir kayıt listesi tanımlanır
Dim articles As IList = New ArrayList
Dim unArticle As Article
While myReader.Read()
'okuyucunun değerleriyle bir ürün hazırlanır
unArticle = New Article
unArticle.id = myReader.GetInt32(0)
unArticle.nom = myReader.GetString(1)
unArticle.prix = myReader.GetDouble(2)
unArticle.stockactuel = myReader.GetInt32(3)
unArticle.stockminimum = myReader.GetInt32(4)
': Ürünü listeye ekleniyor
articles.Add(unArticle)
End While
'sonuç döndürülür
Return articles
Finally
' kaynakların serbest bırakılması
If Not myReader Is Nothing And Not myReader.IsClosed Then myReader.Close()
If Not connexion Is Nothing Then connexion.Close()
End Try
End Function
Private Function executeUpdate(ByVal updateCommand As FbCommand) As Integer
' güncelleme isteğinin yürütülmesi
Try
'BDD'e bağlantı kurulur
connexion.Open()
'sorgu yürütülüyor
Return updateCommand.ExecuteNonQuery()
Finally
' kaynakların serbest bırakılması
If Not connexion Is Nothing Then connexion.Close()
End Try
End Function
End Class
End Namespace
Okuyucunun, bu kodu daha önce yapılan [ArticlesDaoSqlServer] sınıfına ilişkin açıklamalar ışığında okuması önerilir.
2.5.3. [dao] katmanının derlemesinin oluşturulması
Yeni Visual Studio projesi aşağıdaki yapıya sahiptir:

Proje referansları arasında [FirebirdSql.Data.Firebird.dll] derlemesinin bulunduğu dikkat çekmektedir. Bu DLL, projenin [bin] klasörüne yerleştirilmiştir. Proje, [webarticles-dao.dll] adlı bir DLL oluşturmak üzere yapılandırılmıştır:
![]() | ![]() |
2.5.4. [dao] katmanının Nunit testleri
2.5.4.1. NUnit test sınıfı
[ArticlesDaoFirebirdProvider] uygulama sınıfının Nunit test sınıfı, [ArticlesDaoPlainODBC] sınıfınınkiyle aynıdır (bkz. paragraf 2.3.3.2). [ArticlesDaoFirebirdProvider] sınıfının Nunit testini hazırlamak için de benzer bir yaklaşım izliyoruz:
- [dao-firebird-provider] projesinin Visual Studio klasöründe, [dao-odbc] katmanının test projesindeki (solda) [bin] klasörünü kopyalayarak [tests] klasörünü (sağda) oluşturuyoruz:
![]() | ![]() |
- [tests] klasöründe, DLL ve [webarticles-dao.dll] dosyalarını, DLL ve [webarticles-dao.dll] dosyalarıyla değiştiriyoruz; bu dosyalar [dao-firebird-provider]
- [spring-config.xml] yapılandırma dosyasını, yeni [ArticlesDaoFirebirdProvider] sınıfını örneklendirmek üzere değiştiriyoruz:
Yorumlar:
- 7. satırda, [articlesdao] nesnesi artık [ArticlesDaoFirebirdProvider] sınıfının bir örneğiyle ilişkilendirilmiştir
- bu sınıfın dört argümanlı bir oluşturucusu vardır
- SGBD'in ana bilgisayarı - satır 9
- Firebird veritabanına erişim yolu - satır 12
- bağlanan kullanıcının kullanıcı adı - satır 15
- kullanıcının şifresi - satır 18
2.5.4.2. Testler
Veri kaynağındaki [ARTICLES] tablosu aşağıdaki öğelerle doldurulur (IBExpert'i kullanın):

Testlere hazırız. [Nunit-Gui] uygulamasını kullanarak, yukarıdaki [tests] klasöründen DLL ve [test-webarticles-dao.dll] dosyalarını yükleyip [testGetAllArticles] testini çalıştırıyoruz:

Test sınıfına başlangıçta [NUnitTestArticlesDaoArrayList] adı verilmiş olmasına rağmen, burada test edilen sınıf aslında [ArticlesDaoFirebirdProvider]'tir. Ekran görüntüsü, [ARTICLES] tablosuna yerleştirdiğimiz öğeleri doğru bir şekilde aldığımızı göstermektedir. Şimdi tüm testleri yapalım:

Bu belgeyi ekranda görüntüleyen okuyucu, tüm testlerin başarılı olduğunu (yeşil renk) görebilir. Ancak okuyucunun göremeyeceği şey, testlerin ilk uygulamamızdaki ODBC sürücüsü aracılığıyla erişilen ürün tabanına kıyasla çok daha hızlı gerçekleştirilmiş olmasıdır.
2.5.5. Yeni [dao] katmanının [webarticles] uygulamasına entegrasyonu
Daha önce, özellikle 2.3.4. paragrafında iki kez açıklanan yaklaşımı izliyoruz. [runtime] klasörünün içeriğinde aşağıdaki değişiklikleri yapıyoruz:
- [bin] klasöründe,eski katman [dao]'teki DLL, [ArticlesDaoFirebirdProvider] sınıfı tarafından uygulanan yeni katman [dao]'teki DLL ile değiştirilmektedir. Ayrıca, Firebird için gerekli olan DLL'i de [FirebirdSql.Data.Firebird.dll]'e yerleştiriyoruz:

- [runtime] içinde, [web.config] yapılandırma dosyası, yeni uygulama sınıfını dikkate alan bir dosyayla değiştirilir:
Açıklamalar:
- 14-27. satırlar, [articlesDao] tekil nesnesine yeni [ArticlesDaoFirebirdProvider] sınıfının bir örneğini atar. Yapılan tek değişiklik budur.
Testlere hazırız. [Cassini] web sunucusunu önceki testlerdeki gibi yapılandırıyoruz. Ürün tablosunu aşağıdaki değerlerle başlatıyoruz:

Bir tarayıcı kullanarak URL [http://localhost/webarticles/main.aspx] sayfasını çağırıyoruz:

![]() |
Şimdi [ARTICLES] tablosunun içeriğini kontrol edelim:

[crayon bille] ve [ramette 50 feuilles] kalemleri satın alınmış ve stoklarından satın alınan miktar kadar düşülmüştür. [stylo plume] kalemi, talep edilen miktar stoktaki miktarı aştığı için satın alınamamıştır. Okuyucuyu ek testler yapmaya davet ediyoruz.
2.5.6. [ArticlesDaoSqlMap] uygulama sınıfı
2.5.6.1. Ibatis ürünü SqlMap
[webarticles] uygulamamızın [dao] katmanı için dört farklı uygulama yazdık. Her seferinde, diğer iki katman olan [web] ve [domain]'i yeniden derlemeye gerek kalmadan, yeni [dao] katmanını [webarticles] uygulamasına entegre edebildik. Bunu, hatırlayacağınız üzere, iki mimari seçim sayesinde başardık:
- katmanlara arayüzler aracılığıyla erişim
- katmanların Spring ile entegrasyonu
Biraz daha ileri gitmek istiyoruz. Farklı olsalar da, [dao] katmanının dört uygulaması çarpıcı benzerlikler sergiliyor. İlk uygulama yazıldıktan sonra, diğer üçü neredeyse kopyala-yapıştır yoluyla ve bazı anahtar kelimelerin diğerleriyle değiştirilmesiyle elde edildi. Mantık ise değiştirilmedi. Verilere erişimdeki farklı yöntemlerden bizi kurtaracak bir uygulama olmasının mümkün olup olmadığı sorusu akla gelebilir. Dört farklı yöntem kullandık:
- ODBC sürücüsü aracılığıyla ODBC veri kaynağına erişim
- SQL Server veritabanına doğrudan erişim
- Ole Db sürücüsü aracılığıyla bir Ole Db veri kaynağına erişim
- Firebird veritabanına doğrudan erişim
Ibatis SqlMap [[http://www.ibatis.com/]] aracı, veri kaynağının gerçek yapısından bağımsız veri erişim katmanlarının geliştirilmesini mümkün kılar. Veri erişimi aşağıdakiler aracılığıyla sağlanır:
- veri kaynağını ve üzerinde gerçekleştirilmek istenen işlemleri tanımlayan bilgilerin yer aldığı yapılandırma dosyaları
- bu bilgilere dayanarak verilere erişen bir sınıf kütüphanesi
Ibatis SqlMap aracı başlangıçta Java platformu için geliştirilmiştir. .NET platformuna taşınması yakın zamanda gerçekleşmiştir ve görünüşe göre kısmen hatalıdır (kapsamlı bir doğrulama gerektiren kişisel görüş). Bununla birlikte, araç Java platformunda kendini kanıtlamış olduğundan, .NET sürümünü tanıtmak ilgi çekici görünüyor.
2.5.6.2. , IBATIS ve SqlMap nereden bulunabilir?
Firebird’ün ana web sitesi [http://www.ibatis.com/]’tir. İndirme sayfasında şu bağlantılar yer almaktadır:

[Stable Binaries] bağlantısını seçin; bu bağlantı sizi [SourceForge.net] sayfasına yönlendirecektir. İndirme işlemini sonuna kadar takip edin. Aşağıdaki dosyaları içeren bir zip dosyası elde edersiniz:

Ibatis SqlMap kullanan bir Visual Studio projesinde iki şey yapmanız gerekir:
- yukarıdaki dosyaları projenin [bin] klasörüne yerleştirmek
- Projeye bu dosyaların her birine bir referans eklemek
2.5.6.3. Ibatis SqlMap yapılandırma dosyaları
Bir [SqlMap] veri kaynağı, aşağıdaki yapılandırma dosyaları kullanılarak tanımlanacaktır:
- providers.config: verilere erişmek için kullanılacak sınıf kütüphanelerini tanımlar
- sqlmap.config: kurulacak bağlantının özelliklerini tanımlar
- eşleme dosyaları: veriler üzerinde gerçekleştirilecek işlemleri tanımlar
Bu dosyaların işleyişi şu şekildedir:
- Verilere erişmek için bir bağlantıya ihtiyacımız olacak. Bu bağlantıyı temsil etmek üzere, daha önce birkaç sınıfla karşılaşmıştık: OdbcConnection, SqlConnection, OleDbConnection, FbConnection. Ayrıca, SQL isteklerini göndermek için bir [Command] nesnesine de ihtiyacımız olacak: OdbcCommand, SqlCommand, OleDbCommand, FbCommand. Vb. [providers.config] dosyasında, ihtiyacımız olan tüm sınıfları tanımlıyoruz.
- [sqlmap.config] dosyası ise esasen verileri içeren veritabanına bağlantı dizesini tanımlar. Veritabanı bağlantısı, [providers.config] dosyasında tanımlanan [Connection] sınıfının bir örneği oluşturulduğunda açılacaktır; bu sınıfın oluşturucusuna, [sqlmap.config] dosyasında tanımlanan bağlantı dizesi aktarılacaktır.
- Eşleme dosyaları şunları tanımlar:
- veri tablolarındaki satırlar ile .NET sınıfı arasındaki eşleşmeleri; bu sınıfın örnekleri söz konusu satırları içerecektir
- yürütülecek SQL işlemleri. Bunlar bir adla tanımlanır. .NET kodu, bu işlemleri adları aracılığıyla yürütür; bu da .NET kodundaki tüm SQL kodunun ortadan kaldırılmasına yol açar.
2.5.6.4. [dao-sqlmap] projesinin yapılandırma dosyaları
Bir örnek üzerinden, SqlMap yapılandırma dosyalarının tam olarak ne olduğunu inceleyelim. Veri kaynağının, 2.3.3.1. paragrafındaki ODBC Firebird kaynağı olduğu durumu ele alacağız.
2.5.6.4.1. providers.config
ODBC kaynağı için [providers.config] dosyası şöyledir:
Açıklamalar:
- [SqlMap] paketi ile birlikte bir [providers.config] dosyası dağıtılır. Bu dosya, birkaç standart erişim sağlayıcı (provider) sunar. Yukarıdaki kod doğrudan bu dosyadan alınmıştır.
- Bir <provider> öğesinin bir adı vardır (6. satır) ve bu isim herhangi bir şey olabilir
- Bir <provider> etkinleştirilebilir ([enabled=true]) veya etkinleştirilmeyebilir ([enabled=false]). Etkinleştirilmişse, 8. satırda referans verilen DLL'e erişilebilir olmalıdır. Bir [providers.config] dosyası birden fazla <provider> etiketine sahip olabilir.
- 8. satır - 9-15. satırlarda tanımlanan sınıfları içeren derlemenin adı
- 9. satır - bağlantı oluşturmak için kullanılacak sınıf
- 10. satır - SQL komutlarını gönderen bir [Command] nesnesi oluşturmak için kullanılacak sınıf
- 11. satır - parametreleri ayarlanmış bir SQL komutunun parametrelerini yönetmek için kullanılacak sınıf
- satır 12 - bir tablonun alanları için olası veri türlerini sıralayan sınıf
- satır 13 - bu parametrenin değerinin türünü içeren bir [Parameter] nesnesinin özellik adı
- satır 14 - veri kaynağından [DataSet] nesneleri oluşturmaya olanak tanıyan [Adapter] sınıfının adı
- satır 15 - bir [Adapter] nesnesiyle ilişkilendirildiğinde, bu nesnenin [SelectCommand] özelliğinden [InsertCommand, DeleteCommand, UpdateCommand] özelliklerini otomatik olarak oluşturmaya olanak tanıyan [CommandBuilder] sınıfının adı
- 16 - 19. satırlar - parametreleri ayarlanmış SQL komutlarının nasıl yönetileceği tanımlanır. Duruma göre, örneğin şunu yazmak gerekir:
ya da
İlk durumda, biçimsel konum parametrelerinden söz edilir. Bunların gerçek değerleri, biçimsel parametrelerin sırasına göre sağlanmalıdır. İkinci durumda ise adlandırılmış parametrelerle ilgileniyoruz. Bu tür bir parametreye, adını belirterek bir değer verilir. Sıra artık önemli değildir.
- 16. satır - ODBC kaynaklarının konumsal parametreler kullandığı belirtilir
- 17-19. satırlar - adlandırılmış parametrelerle ilgilidir. Burada böyle bir parametre yoktur.
Bu bilgiler, SqlMap'in örneğin bir bağlantı oluşturmak için hangi sınıfı örneklendirmesi gerektiğini bilmesini sağlar. Burada bu, [OdbcConnection] sınıfı olacaktır (9. satır).
2.5.6.4.2. sqlmap.config
[providers.config] dosyası, bir ODBC kaynağına erişmek için kullanılacak sınıfları tanımlar. Hiçbir ODBC kaynağı belirtmez. Bunu yapan dosya [sqlmap.config]'tir:
Açıklamalar:
- 3. satır - [properties.xml] adlı bir özellik dosyası tanımlanmaktadır. Bu dosya, (anahtar, değer) çiftlerini tanımlar. Anahtarlar herhangi bir değer alabilir. C anahtarına atanan değer, [sqlmap.config] dosyasında ${C} notasyonu ile elde edilir. İşte önceki [sqlmap.config] dosyasına eşleştirilecek olan [properties.xml] dosyası:
-
satır - [provider] anahtarı tanımlanmıştır. Değeri, [providers.config] dosyasında kullanılacak <provider> etiketinin adıdır
-
satır - [connectionString] anahtarı tanımlanmıştır. Değeri, ODBC Firebird veri kaynağına bağlantı kurmak için kullanılacak bağlantı dizesidir.
- 4-7. satırlar - yapılandırma parametreleri:
- 5. satır - SQL sorguları, kendisi de bir ad alanının parçası olabilen bir adla tanımlanacaktır. [useStatementNamespaces="false"], ad alanlarının kullanılmayacağını belirtir.
- 6. satır - SqlMap, veri kaynağına erişimi en aza indirmek için çeşitli önbellek stratejilerine sahiptir. [cacheModelsEnabled="false"], hiçbirinin kullanılmayacağını belirtir.
- 9-13. satırlar - veri kaynağının özellikleri tanımlanır:
- 10. satır - kullanılacak [providers.config] <provider>'ının adı
- 11. satır - veri kaynağına bağlantı dizesi
- 12. satır - işlem yöneticisi. Burada bunu kullanmadık, ancak standart dağıtım dosyasında yer aldığı için satırı yine de bıraktık.
- 14-16. satırlar - veri kaynağı üzerinde gerçekleştirilecek SQL işlemlerini tanımlayan dosyaların listesi.
- 15. satır - [articles.xml] eşleme dosyasını tanımlar
2.5.6.4.3. articles.xml
Bu dosya iki işleve sahiptir:
- veri kaynağındaki tabloların nesne eşlemesini tanımlamak. En basit durumlarda bu, bir sınıfı bir tablonun satırıyla ilişkilendirmek anlamına gelir.
- parametreli SQL işlemlerini tanımlamak ve bunlara isim vermek.
Aşağıdaki [articles.xml] dosyasını kullanacağız:
Açıklamalar:
- 4-11. satırlar - veri kaynağındaki [ARTICLES] tablosunun bir satırı ile [istia.st.articles.dao.Article] sınıfı arasında bir eşleme tanımlanır. Tablonun her sütununa (column), [Article] sınıfının bir özelliği (property) eşleştirilir. Bu eşleme, [SqlMap]'in SQL SELECT işleminin sonucunu oluşturmasına olanak tanır. SELECT'in her bir sonuç satırı, eşleme kurallarına göre bir [Article] nesnesine yerleştirilecektir.
- 5. satır - eşleme, <resultMap> etiketiyle belirtilir ve [id="article"] özniteliği ile adlandırılır. İlişkili sınıf, [class="istia.st.articles.dao.Article"] özniteliği ile belirtilir.
- 14-44. satırlar - İhtiyaç duyulan SQL işlemlerini tanımlıyoruz
- 16-18. satırlar - [getAllArticles] olarak adlandırılan SELECT işlemi tanımlanır
- 16. satır - SELECT işlemi, [name= "getAllArticles "] olarak adlandırılır ve kullanılacak eşleme, [resultMap="article"] özniteliği ile tanımlanır. Dolayısıyla burada 5-11. satırlardaki eşlemeye atıfta bulunulmaktadır
- 17. satır - çalıştırılacak SQL komutunun metni
- 20-22. satırlar - ürün tablosunu boşaltmak için [clearAllArticles] SQL-Delete komutu tanımlanır.
- 24-27. satırlar - ürün tablosuna yeni bir ürün eklemek amacıyla kullanılan SQL-Insert komutu [insertArticle] tanımlanmaktadır. Bu, (#id#, #ad#, #fiyat#, #mevcutstok#, #asgari stok#) öğeleriyle parametreleştirilen bir sorgudur. Bu beş öğenin değerleri, parametre olarak geçirilen [Article] nesnesinden alınacaktır: [parameterClass="istia.st.articles.dao.Article"]. Parametre nesnesi, parametreleri ayarlanmış SQL komutunda referans verilen (id, isim, fiyat, mevcutstok, minimumstok) özelliklere sahip olmalıdır.
- 29-31. satırlar - #value# numarası bilinen bir ürünü silmek için SQL Delete [deleteArticle] komutu tanımlanır. Bu numara parametre olarak aktarılacaktır: [parameterClass="int"]. Bu genel bir kuraldır. Parametre tek olduğunda, SQL komut metninde #value# anahtar sözcüğüyle referans verilir.
- 33-35. satırlar - numarası bilinen bir ürünü değiştirmek için kullanılan SQL-Update komutu [modifyArticle] tanımlanır. [insertArticle] komutunda olduğu gibi, gerekli beş bilgi bir [istia.st.articles.dao.Article] nesnesinin özelliklerinden alınacaktır.
- satır 37-39 - numarası bilinen bir ürünün satırını elde etmeyi sağlayan [getArticleById] SQL-Select komutu tanımlanmaktadır.
- 41-43. satırlar - numarası bilinen bir ürünün [stockactuel] alanını değiştiren [changerStockArticle] SQL-Update komutu tanımlanmaktadır. Gerekli olan iki bilgi, yani ürünün #id# numarası ve stoktaki #mouvement# artış değeri, [parameterClass="Hashtable"] adlı bir sözlükte bulunur. Bu sözlükte id ve mouvement olmak üzere iki anahtar bulunmalıdır. SQL komutunda kullanılacak değerler, bu iki anahtara atanan değerlerdir.
2.5.6.4.4. Yapılandırma dosyalarının konumu
İki farklı durumu ele alacağız:
- Nunit testi durumunda, [SqlMap] yapılandırma dosyaları, test edilen ikili dosyalarla aynı klasöre yerleştirilecektir.
- Bir web uygulaması söz konusu olduğunda, bu dosyalar uygulamanın kök dizinine yerleştirilecektir.
2.5.6.5. API ve SqlMap
SqlMap sınıfları, genellikle uygulamanın [bin] klasörüne yerleştirilen DLL içinde bulunur:

SqlMap sınıflarını kullanan uygulamalar, [IBatisNet.DataMapper] ad alanını içe aktarmalıdır:
Tüm SQL işlemleri, [IBatisNet.DataMapper ] ad alanına ait bir sınıf olan [Mapper] türünde bir singleton aracılığıyla gerçekleştirilir. Singleton şu şekilde elde edilir:
SqlMap [getAllArticles] komutunu çalıştırmak için şu kod yazılır:
- [QueryForList] yöntemi, bir SELECT komutunun sonucunu bir listede elde etmeyi sağlar
- ilk parametre, çalıştırılacak SQL komutunun adıdır (bkz. articles.xml)
- ikinci parametre, SQL isteğine iletilecek parametredir. SqlMap komutunun [parameterClass] özniteliğiyle eşleşmelidir. [articles.xml]'te [parameterClass=Nothing] bulunur. Bu nedenle buraya sıfır işaretçisi aktarılır.
- Sonuç, IList türündedir. Bu listedeki nesneler, SQL-select komutundaki [resultMap] özniteliği ile belirtilir: [resultMap="article"]. "article", bir eşleme adıdır:
Bu eşlemeye ilişkin sınıf [istia.st.articles.dao.Article]'tir. Sonuç olarak, yukarıda tanımlanan [articles] değişkeni, [ istia.st.articles.dao.Article] nesnelerinden oluşan bir listedir. Böylece tek bir komutla [ARTICLES] tablosunun tamamını elde ettik. [ARTICLES] tablosu boşsa, 0 öğe içeren bir [IList] nesnesi elde edilir.
SqlMap [getArticleById] komutunu çalıştırmak için şunu yazacağız:
- [QueryForObject] yöntemi, yalnızca bir satır döndüren SELECT komutunun sonucunu elde etmeyi sağlar
- ilk parametre, çalıştırılacak SqlMap komutunun adıdır
- ikinci parametre, SQL isteğine iletilecek parametredir. SqlMap komutunun [parameterClass] özniteliğiyle eşleşmelidir. [articles.xml] komutunda [parameterClass="int"] değerine rastlanır. Bu nedenle buraya, aranan ürünün numarasını temsil eden bir tamsayı aktarılır.
- Sonuç, Object türündedir. SELECT komutu hiçbir satır döndürmediyse, sonuç olarak null (nothing) işaretçisi elde edilir.
SqlMap [insertArticle] komutunu çalıştırmak için şunu yazacağız:
- [Insert] yöntemi, SQL ve INSERT komutlarını çalıştırmaya olanak tanır
- ilk parametre, çalıştırılacak SqlMap komutunun adıdır
- ikinci parametre ise komuta iletilecek parametredir. SqlMap komutunun [parameterClass] özniteliğiyle eşleşmelidir. [articles.xml] komutunda [parameterClass="istia.st.articles.dao.Article"] bulunur. Bu nedenle buraya [istia.st.articles.dao.Article] türünde bir nesne aktarılır.
SqlMap komutunu [deleteArticle] ile çalıştırmak için şunu yazacağız:
- [Delete] yöntemi, SQL ve DELETE komutlarını çalıştırmaya olanak tanır
- ilk parametre, çalıştırılacak SQL komutunun adıdır
- ikinci parametre ise bu komuta iletilecek parametredir. SqlMap komutunun [parameterClass] özniteliğiyle eşleşmelidir. [articles.xml] komutunda [parameterClass="int"] yer almaktadır. Bu nedenle buraya silinecek ürün numarası girilir.
- [Delete] yönteminin sonucu, silinen satır sayısıdır
Benzer şekilde, SqlMap [clearAllArticles] komutunu çalıştırmak için şunu yazacağız:
SqlMap [modifyArticle] komutunu çalıştırmak için şunu yazın:
- [Update] yöntemi, SQL ve UPDATE komutlarını çalıştırmaya olanak tanır
- ilk parametre, çalıştırılacak SqlMap komutunun adıdır
- ikinci parametre ise bu komuta iletilecek parametredir. SqlMap komutunun [parameterClass] özniteliğiyle eşleşmelidir. [articles.xml] komutunda [parameterClass="istia.st.articles.dao.Article"] bulunur. Bu nedenle buraya [istia.st.articles.dao.Article] türünde bir nesne aktarılır.
- [Update] yönteminin sonucu, değiştirilen satır sayısıdır.
Benzer şekilde, SqlMap [changerStockArticle] komutunu çalıştırmak için şunu yazacağız:
Dim paramètres As New Hashtable(2)
paramètres("id") = idArticle
paramètres("mouvement") = mouvement
' güncelleme
dim nbLignes as Integer= mappeur.Update("changerStockArticle", paramètres)
- İkinci parametre, SqlMap komutunun [parameterClass] özniteliğine karşılık gelir. [articles.xml]'te ise [parameterClass="Hashtable"] bulunur. SQL komutu, [changerStockArticle] olarak ayarlanmış olup, [id, mouvement] parametrelerini kullanır. Bu nedenle burada bu iki anahtarı içeren bir sözlük aktarılır.
2.5.6.6. [ArticlesDaoSqlMap] sınıfının kodu
Yukarıdaki açıklamaların ardından, artık aşağıdaki yeni [ArticlesDaoSqlMap] uygulama sınıfını yazabiliriz:
Option Explicit On
Option Strict On
Imports System
Imports IBatisNet.DataMapper
Imports System.Collections
Namespace istia.st.articles.dao
Public Class ArticlesDaoSqlMap
Implements IArticlesDao
' özel alanlar
Dim mappeur As SqlMapper = Mapper.Instance
' tüm makalelerin listesi
Public Function getAllArticles() As IList Implements IArticlesDao.getAllArticles
SyncLock Me
Try
Return mappeur.QueryForList("getAllArticles", Nothing)
Catch ex As Exception
Throw New Exception("Echec de l'obtention de tous les articles : [" + ex.ToString + "]")
End Try
End SyncLock
End Function
' makale ekleme
Public Function ajouteArticle(ByVal unArticle As Article) As Integer Implements IArticlesDao.ajouteArticle
SyncLock Me
Try
' unArticle : eklenecek makale
' ekleme
mappeur.Insert("insertArticle", unArticle)
Return 1
Catch ex As Exception
Throw New Exception("Echec de l'ajout de l'article [" + unArticle.ToString + "] : [" + ex.ToString + "]")
End Try
End SyncLock
End Function
' bir ürünü siler
Public Function supprimeArticle(ByVal idArticle As Integer) As Integer Implements IArticlesDao.supprimeArticle
SyncLock Me
Try
' id: silinecek ürünün kimliği
' silme
Return mappeur.Delete("deleteArticle", idArticle)
Catch ex As Exception
Throw New Exception("Erreur lors de la suppression de l'article d'id [" + idArticle.ToString + "] : [" + ex.ToString + "]")
End Try
End SyncLock
End Function
' bir ürünü değiştir
Public Function modifieArticle(ByVal unArticle As Article) As Integer Implements IArticlesDao.modifieArticle
SyncLock Me
Try
' güncelleme
Return mappeur.Update("modifyArticle", unArticle)
Catch ex As Exception
Throw New Exception("Erreur lors de la mise à jour de l'article [" + unArticle.ToString + "] : [" + ex.ToString + "]")
End Try
End SyncLock
End Function
' makale arama
Public Function getArticleById(ByVal idArticle As Integer) As Article Implements IArticlesDao.getArticleById
SyncLock Me
Try
' id: aranan ürünün kimliği
Return CType(mappeur.QueryForObject("getArticleById", idArticle), Article)
Catch ex As Exception
Throw New Exception("Erreur lors de la recherche de l'article d'id [" + idArticle.ToString + "] : [" + ex.ToString + "]")
End Try
End SyncLock
End Function
' tüm ürünlerin silinmesi
Public Sub clearAllArticles() Implements IArticlesDao.clearAllArticles
SyncLock Me
Try
mappeur.Delete("clearAllArticles", Nothing)
Catch ex As Exception
Throw New Exception("Erreur lors de l'effacement de la table des articles : [" + ex.ToString + "]")
End Try
End SyncLock
End Sub
' bir ürünün stokunu değiştirme
Public Function changerStockArticle(ByVal idArticle As Integer, ByVal mouvement As Integer) As Integer Implements IArticlesDao.changerStockArticle
SyncLock Me
Try
' id: stok durumu değiştirilen ürünün kimliği
' hareket: stok hareketi
Dim paramètres As New Hashtable(2)
paramètres("id") = idArticle
paramètres("mouvement") = mouvement
' güncelleme
Return mappeur.Update("changerStockArticle", paramètres)
Catch ex As Exception
Throw New Exception(String.Format("Erreur lors du changement de stock [{0},{1}] : {2}", idArticle, mouvement, ex.ToString))
End Try
End SyncLock
End Function
End Class
End Namespace
Okuyucunun, bu kodu SqlMap için verilen açıklamalar ışığında okuması önerilir. [SqlMap]'in kullanılmasıyla yazılması gereken kod miktarının önemli ölçüde azaldığı dikkat çekicidir.
2.5.6.7. [dao] katmanının derlemesinin oluşturulması
Yeni Visual Studio projesi aşağıdaki yapıya sahiptir:

Proje referanslarında SqlMap için gerekli "assembly"lerin bulunduğu dikkat çekmektedir. Bu DLL'ler, projenin [bin] klasörüne yerleştirilmiştir. Proje, DLL adlı bir [webarticles-dao.dll] dosyası oluşturacak şekilde yapılandırılmıştır:
![]() | ![]() |
2.5.6.8. [dao] katmanının Nunit testleri
2.5.6.8.1. NUnit test sınıfı
[ArticlesDaoSqlMap] uygulama sınıfının Nunit test sınıfı, [ArticlesDaoPlainODBC] sınıfınınkiyle aynıdır (bkz. paragraf 2.3.3.2). [ArticlesDaoSqlMap] sınıfının Nunit testini hazırlamak için de benzer bir yaklaşım izliyoruz:
- [dao-sqlmap] projesinin Visual Studio klasöründe, [dao-odbc] projesindeki (solda) [tests] klasörünü kopyalayarak [test1] klasörünü (sağda) oluşturuyoruz:
![]() | ![]() |
- [tests] klasöründe, DLL ve [webarticles-dao.dll] dosyalarını, DLL ve [webarticles-dao.dll] dosyalarıyla değiştiriyoruz; bu dosyalar [dao-sqlmap] projesinin oluşturulması sırasında elde edilen DLL ve [webarticles-dao.dll] ile değiştiriyoruz.
- SqlMap için gerekli olan DLL'leri ve incelenen yapılandırma dosyaları [providers.config, sqlmap.config, properties.xml, articles.xml]'i ekliyoruz.
- Yeni [ArticlesDaoSqlMap] sınıfını oluşturmak için [spring-config.xml] yapılandırma dosyasını değiştiriyoruz:
Açıklamalar:
- 7. satırda, [articlesdao] nesnesi artık [ArticlesDaoSqlMap] sınıfının bir örneğiyle ilişkilendirilmiştir
- Bu sınıfın oluşturucusu yoktur. Varsayılan oluşturucu kullanılacaktır.
2.5.6.8.2. Tests
Firebird veri kaynağındaki [ARTICLES] tablosu aşağıdaki öğelerle doldurulmuştur:

Testlere hazırız. [Nunit-Gui] uygulamasını kullanarak, yukarıdaki [test1] klasöründen DLL ve [test-webarticles-dao.dll] dosyalarını yükleyip [testGetAllArticles] testini çalıştırıyoruz:

Test sınıfına başlangıçta [NUnitTestArticlesDaoArrayList] adı verilmiş olmasına rağmen, burada test edilen sınıf aslında [ArticlesDaoSqlMap]'tir. Ekran görüntüsü, [ARTICLES] tablosuna yerleştirdiğimiz öğeleri doğru bir şekilde aldığımızı göstermektedir. Şimdi tüm testleri yapalım:

Bu belgeyi ekranda görüntüleyen okuyucu, bazı testlerin başarılı olduğunu (yeşil renk), bazılarının ise başarısız olduğunu (kırmızı renk) görebilir. Başarısız olan testler [testArticleAbsent] ve [testChangerStockArticle] testleridir. Uzun araştırmaların ardından, bu başarısızlıkların nedenlerinin şunlar olduğu anlaşılmaktadır:
- [testArticleAbsent] testinde, mevcut olmayan bir makalenin değiştirilmesi istenmektedir. Bunun için [modifieArticle] yöntemi kullanılıyor; bu yöntem, değiştirilen satır sayısını 0 veya 1 olarak döndürüyor. Burada değerin 0 olması gerekirken, bunun yerine [IBatisNet.Common.Exceptions.ConcurrentException] türünde bir istisna oluşuyor.
- [changerStockArticle]'te yine [update] türünde bir işlem var. Bu işlem, stok miktarından stok miktarından daha büyük bir miktarı düşürmeyi içeriyor. Bunun için, değiştirilen satır sayısını 0 veya 1 yapan [changerStockArticle] yöntemi kullanılır. SQL komutu, stoğu negatif hale getirecek bir güncellemeyi önlemek için yazılmıştır (bkz. articles.xml içindeki SQL "changerStockArticle" komutu). Burada, [changerStockArticle] yönteminin sonucu olarak 0 değerinin elde edilmesi beklenmektedir. Yine, [IBatisNet.Common.Exceptions.ConcurrentException] türünde bir istisna ile karşılaşıyoruz.
Olası hata kaynakları çoktur:
- [ArticlesDaoSqlMap] sınıfının kodu hatalı. Bu mümkün. Ancak bu kod, SqlMap'in Java sürümünde düzgün çalışmış olan bir Java sınıfının uyarlanmasından kaynaklanıyor.
- SqlMap'in .NET sürümünde hata var
- Firebird'ün ODBC sürücüsünde hata var
- ...
Kesin bir bilgi olmadığı için, söz konusu [IBatisNet.Common.Exceptions.ConcurrentException] istisnasını yakalayarak bu engeli aşacağız. [ArticlesDaoSqlMap] sınıfının yeni kodu şu şekilde olur:
Değişiklikler 28, 41 ve 69. satırlarda yapılmıştır. [UPDATE, DELETE] türündeki SQL işlemleri için, [IBatisNet.Common.Exceptions.ConcurrentException] türünde bir istisna meydana gelirse, sonuç olarak 0 değerini döndürürüz; böylece hiçbir satırın değiştirilmediğini veya silinmediğini belirtmiş oluruz. Bunun ardından, projenin DLL dosyası yeniden oluşturulur, [test1] klasörüne yerleştirilir ve NUnit testleri yeniden çalıştırılır:

Bu sefer başarılı oldu. Artık bu DLL ile çalışacağız.
2.5.6.9. Yeni [dao] katmanının [webarticles] uygulamasına entegrasyonu
2.5.6.9.1. ODBC veri kaynağı
Burada, 2.3.3.1. paragrafında incelenen ODBC veri kaynağını test ediyoruz. Bu veri kaynağı burada SqlMap aracılığıyla kullanılmaktadır.
2.3.4. paragrafındaki yaklaşımı izliyoruz. [runtime] klasörünün içeriğinde aşağıdaki değişiklikleri yapıyoruz:
- [bin] klasöründe,eski katman [dao]'teki DLL, [ArticlesDaoSqlMap] sınıfı tarafından uygulanan yeni katman [dao]'teki DLL ile değiştirilir. Buna, Firebird için gerekli olan DLL ve SqlMap katmanlarını da ekliyoruz:

- [runtime] dizinine, SqlMap ve [providers.config, sqlmap.config, properties.xml, articles.xml] yapılandırma dosyaları yerleştirilir:

- [runtime] içinde, [web.config] yapılandırma dosyası, yeni uygulama sınıfını dikkate alan bir dosyayla değiştirilir:
Açıklamalar:
- 14. satırda, [articlesDao] tekil nesnesine yeni [ArticlesDaoSqlMap] sınıfının bir örneği atanır. Yapılan tek değişiklik budur.
Testlere hazırız. [Cassini] web sunucusunu önceki testlerdeki gibi yapılandırıyoruz. Makale tablosunu aşağıdaki değerlerle başlatıyoruz:

Bir tarayıcı kullanarak URL ve [http://localhost/webarticles/main.aspx] sayfalarını çağırıyoruz:

![]() |
Şimdi [ARTICLES] tablosunun içeriğini kontrol edelim:

[couteau] ve [cuiller] kalemleri satın alınmış ve stoklarından satın alınan miktar kadar düşülmüştür. [fourchette] kalemi, talep edilen miktar stoktaki miktarı aştığı için satın alınamamıştır. Okuyucuyu ek testler yapmaya davet ediyoruz.
2.5.6.9.2. MSDE veri kaynağı
Burada, 2.4.3.1. paragrafında incelenen MSDE veri kaynağını test ediyoruz. Bu veri kaynağı burada SqlMap aracılığıyla kullanılmaktadır. Öncekiyle aynı yaklaşımı izliyoruz. [runtime] dosyasının içeriğinde aşağıdaki değişiklikleri yapıyoruz:
- [bin] klasörünün içeriği değişmiyor
- [runtime] içinde, SqlMap ve [providers.config, properties.xml] yapılandırma dosyaları değişir. [sqlmap.config, articles.xml] yapılandırma dosyaları değişmez.
- [providers.config] dosyası yeni bir <provider> yapılandırır:
<?xml version="1.0" encoding="utf-8" ?>
<providers>
<clear/>
<provider
name="sqlServer1.1"
assemblyName="System.Data, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
connectionClass="System.Data.SqlClient.SqlConnection"
commandClass="System.Data.SqlClient.SqlCommand"
parameterClass="System.Data.SqlClient.SqlParameter"
parameterDbTypeClass="System.Data.SqlDbType"
parameterDbTypeProperty="SqlDbType"
dataAdapterClass="System.Data.SqlClient.SqlDataAdapter"
commandBuilderClass="System.Data.SqlClient.SqlCommandBuilder"
usePositionalParameters = "false"
useParameterPrefixInSql = "true"
useParameterPrefixInParameter = "true"
parameterPrefix="@"
/>
</providers>
Bu <provider>, SQL Sunucusunun veri kaynaklarına erişim için .NET sınıflarını kullanır. [providers.config] şablon dosyasında standart olarak entegre edilmiştir ve SqlMap ile birlikte dağıtılır.
- [properties.xml] dosyası, MSDE kaynağının <provider> öğesini ve bu kaynağın bağlantı dizesini tanımlar:
<?xml version="1.0" encoding="utf-8" ?>
<settings>
<add key="provider" value="sqlServer1.1" />
<add
key="connectionString"
value="Data Source=portable1_tahe\msde140405;Initial Catalog=dbarticles;UID=admarticles;PASSWORD=mdparticles;"/>
</settings>
- [runtime]'te, [web.config] yapılandırma dosyası değişmez.
Testlere hazırız. [Cassini] web sunucusu normal yapılandırmasını korur. MSDE kaynak tablosunu [EMS MS SQL Manager] ile başlatıyoruz:

Bir tarayıcı kullanarak URL ve [http://localhost/webarticles/main.aspx] sayfalarını çağırıyoruz:

![]() |
Şimdi [ARTICLES] tablosunun içeriğini [EMS MS SQL Manager] ile karşılaştıralım:

[ballon foot] ve [raquette tennis] kalemleri satın alınmış ve stoklarından satın alınan miktar kadar düşülmüştür. [rollers] kalemi, talep edilen miktar stoktaki miktarı aştığı için satın alınamamıştır. Okuyucuyu ek testler yapmaya davet ediyoruz.
2.5.6.9.3. OleDb veri kaynağı
Burada, 2.4.5.1. paragrafında sunulan ACCESS veri kaynağını test ediyoruz. Bu veri kaynağı burada SqlMap aracılığıyla kullanılmaktadır. Öncekiyle aynı yaklaşımı izliyoruz. [runtime] dosyasının içeriğinde aşağıdaki değişiklikleri yapıyoruz:
- [bin] klasörünün içeriği değişmiyor
- [runtime] içinde, SqlMap ve [providers.config, properties.xml] yapılandırma dosyaları değişir. [sqlmap.config, articles.xml] yapılandırma dosyaları değişmez.
- [providers.config] dosyası yeni bir <provider> yapılandırır:
<?xml version="1.0" encoding="utf-8" ?>
<providers>
<clear/>
<provider
name="OleDb1.1"
enabled="true"
assemblyName="System.Data, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
connectionClass="System.Data.OleDb.OleDbConnection"
commandClass="System.Data.OleDb.OleDbCommand"
parameterClass="System.Data.OleDb.OleDbParameter"
parameterDbTypeClass="System.Data.OleDb.OleDbType"
parameterDbTypeProperty="OleDbType"
dataAdapterClass="System.Data.OleDb.OleDbDataAdapter"
commandBuilderClass="System.Data.OleDb.OleDbCommandBuilder"
usePositionalParameters = "true"
useParameterPrefixInSql = "false"
useParameterPrefixInParameter = "false"
parameterPrefix = ""
/>
</providers>
Bu <provider>, OleDb veri kaynaklarına erişim için .NET sınıflarını kullanır. SqlMap ile birlikte dağıtılan [providers.config] şablon dosyasına standart olarak entegre edilmiştir.
- [properties.xml] dosyası, OleDb kaynağının <provider> öğesini ve bu kaynağın bağlantı dizesini tanımlar:
<?xml version="1.0" encoding="utf-8" ?>
<settings>
<add key="provider" value="OleDb1.1" />
<add
key="connectionString"
value="Provider=Microsoft.Jet.OLEDB.4.0;Data Source=D:\data\serge\databases\access\articles\articles.mdb;"/>
</settings>
- [runtime]'te, [web.config] yapılandırma dosyası değişmez.
Testlere hazırız. [Cassini] web sunucusu normal yapılandırmasını korur. ACCESS kaynağındaki ürün tablosunu şu şekilde başlatıyoruz:

Bir tarayıcıyla URL [http://localhost/webarticles/main.aspx] adresini çağırıyoruz:

![]() |
Şimdi [ARTICLES] tablosunun içeriğini şu komutla kontrol edelim:

[pantalon] ve [jupe] kalemleri satın alınmış ve stoklarından satın alınan miktar kadar düşülmüştür. [manteau] kalemi, talep edilen miktar stoktaki miktarı aştığı için satın alınamamıştır. Okuyucuyu ek testler yapmaya davet ediyoruz.
2.5.7. Sonuç
Bu uzun eğitim makalesini burada sonlandırıyoruz. Ne yaptık?
- Dört farklı yolla, üç katmanlı bir web uygulamasının [dao] katmanını hayata geçirdik:
- ODBC kaynaklarına erişim için .NET erişim sınıflarını kullanarak
- SQL Server kaynaklarına erişim sınıfları .NET'i kullanarak
- .NET erişim sınıflarını kullanarak OleDb kaynaklarına erişmek
- Firebird veritabanına erişmek için üçüncü taraf erişim sınıflarını kullanarak
- her seferinde, üç katmanlı [web, domain, dao] uygulamasına yeni [dao] katmanını entegre ettik, hiçbir [web, domain] katmanını yeniden derlemeden
- son olarak, kod açısından şeffaf bir şekilde farklı veri kaynaklarına uyum sağlayabilen bir [dao] katmanı oluşturmamızı sağlayan [SqlMap] aracını sunduk. Böylece bu yeni katman sayesinde, önceki 1 ila 3 numaralı uygulamaların veri kaynaklarını art arda kullanabildik. Bu işlem, yapılandırma dosyaları yardımıyla şeffaf bir şekilde gerçekleştirildi.
- Spring ve SqlMap araçlarının üç katmanlı web uygulamalarına sağladığı büyük esnekliği gösterdik.































































