Skip to content

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ü

Image

2.2.2. Uygulamanın genel mimarisi

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

  1. 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.
  2. 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.
  3. 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ı
  4. 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.
  5. 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:

  1. iş sınıfları
  2. veri erişim sınıfları
  3. 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);
id
bir ürünü benzersiz bir şekilde tanımlayan birincil anahtar
nom
ürün adı
prix
ürünün fiyatı
stockactuel
mevcut stok durumu
stockminimum
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:

Image

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]

Image

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

  1. bir öğenin 5 bilgisini belirlemeye yarayan bir oluşturucu: [id, nom, prix, stockactuel, stockminimum]
  2. bu 5 bilgiyi okumak ve yazmak için kullanılan genel özellikler.
  3. ürüne girilen verilerin doğrulanması. Verilerde hata olması durumunda bir istisna atılır.
  4. 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:

getAllArticles
veri kaynağındaki tüm makaleleri döndürür
clearAllArticles
veri kaynağını boşaltır
getArticleById
numarasıyla tanımlanan [Article] nesnesini döndürür
ajouteArticle
veri kaynağına bir öğe eklemeye izin verir
modifieArticle
veri kaynağındaki bir öğeyi değiştirmeye olanak tanır
supprimerArticle
veri kaynağından bir öğeyi silmeye olanak tanır
changerStockArticle
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:

Imports System
Imports System.Collections
Imports System.Data.Odbc

Namespace istia.st.articles.dao

    Public Class ArticlesDaoPlainODBC
        Implements istia.st.articles.dao.IArticlesDao

         ' özel alanlar
        Private connexion As OdbcConnection = Nothing
        Private DSN As String
        Private insertCommand As OdbcCommand
        Private updatecommand As OdbcCommand
        Private deleteSomeCommand As OdbcCommand
        Private selectSomeCommand As OdbcCommand
        Private updateStockCommand As OdbcCommand
        Private deleteAllCommand As OdbcCommand
        Private selectAllCommand As OdbcCommand

         ' üretici
        Public Sub New(ByVal DSN As String, ByVal uid As String, ByVal password As String)
             ' DSN: kaynak adı ODBC
             ' uid: kullanıcı kimliği
             ' şifre: şifresi
...
        End Sub

        Public Function ajouteArticle(ByVal unArticle As Article) As Integer Implements IArticlesDao.ajouteArticle
...
        End Function

        Public Function changerStockArticle(ByVal idArticle As Integer, ByVal mouvement As Integer) As Integer Implements IArticlesDao.changerStockArticle
...
        End Function

        Public Sub clearAllArticles() Implements IArticlesDao.clearAllArticles
...
        End Sub

        Public Function getAllArticles() As System.Collections.IList Implements IArticlesDao.getAllArticles
...
        End Function

        Public Function getArticleById(ByVal idArticle As Integer) As Article Implements IArticlesDao.getArticleById
...
        End Function

        Public Function modifieArticle(ByVal unArticle As Article) As Integer Implements IArticlesDao.modifieArticle
...
        End Function

        Public Function supprimeArticle(ByVal idArticle As Integer) As Integer Implements IArticlesDao.supprimeArticle
....
        End Function

        Private Function executeQuery(ByVal query As OdbcCommand) As IList
             ' bir sorgunun yürütülmesi SELECT 
....
        End Function

        Private Function executeUpdate(ByVal sqlCommand As OdbcCommand) As Integer
....
    End Class

End Namespace

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

         ' oluşturucu
        Public Sub New(ByVal DSN As String, ByVal uid As String, ByVal password As String)
             ' DSN: kaynak adı ODBC
             ' uid: kullanıcı kimliği
             ' şifre: şifresi

             ': argüman olarak geçirilen veritabanı adı alınır
            Me.DSN = DSN
            Dim connectString As String = String.Format("DSN={0};UID={1};PASSWORD={2}", DSN, uid, password)
             'bağlantı örneği oluşturulur
            connexion = New OdbcConnection(connectString)
             ' sorgular hazırlanıyor SQL
            insertCommand = New OdbcCommand("insert into ARTICLES(id, nom, prix, stockactuel, stockminimum) values (?,?,?,?,?)", connexion)
            updatecommand = New OdbcCommand("update ARTICLES set nom=?, prix=?, stockactuel=?, stockminimum=? where id=?", connexion)
            deleteSomeCommand = New OdbcCommand("delete from ARTICLES where id=?", connexion)
            selectSomeCommand = New OdbcCommand("select id, nom, prix, stockactuel, stockminimum from ARTICLES where id=?", connexion)
            updateStockCommand = New OdbcCommand("update ARTICLES set stockactuel=stockactuel+? where id=? and (stockactuel+?)>=0", connexion)
            selectAllCommand = New OdbcCommand("select id, nom, prix, stockactuel, stockminimum from ARTICLES", connexion)
            deleteAllCommand = New OdbcCommand("delete from ARTICLES", connexion)
        End Sub

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

        Private Function executeQuery(ByVal query As OdbcCommand) As IList
             ' bir sorgu çalıştırılır SELECT 
             ' sonuç tablosundaki tüm satırlara erişim sağlayan nesnenin tanımlanması
            Dim myReader As OdbcDataReader = 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

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

        Private Function executeUpdate(ByVal sqlCommand As OdbcCommand) 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

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

        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 OdbcParameter("id", unArticle.id))
                    .Add(New OdbcParameter("nom", unArticle.nom))
                    .Add(New OdbcParameter("prix", unArticle.prix))
                    .Add(New OdbcParameter("stockactuel", unArticle.stockactuel))
                    .Add(New OdbcParameter("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

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

        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 OdbcParameter("nom", unArticle.nom))
                    .Add(New OdbcParameter("prix", unArticle.prix))
                    .Add(New OdbcParameter("stockactuel", unArticle.stockactuel))
                    .Add(New OdbcParameter("stockminimum", unArticle.stockminimum))
                    .Add(New OdbcParameter("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

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

        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 OdbcParameter("id", idArticle))
                End With
                 'çalıştırı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

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

            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

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

        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 OdbcParameter("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ığı kontrol ediliyor
                    If articles.Count = 0 Then Return Nothing
                     ', ürünü döndürüyoruz
                    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

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

        Public Sub clearAllArticles() Implements IArticlesDao.clearAllArticles
             ' özel bölüm
            SyncLock Me
                Try
                     'silme sorgusu yürütülüyor
                    executeUpdate(deleteAllCommand)
                Catch ex As Exception
                     'istek hatası
                    Throw New Exception(String.Format("Erreur lors de la suppression des articles : {0}", ex.Message))
                End Try
            End SyncLock
        End Sub

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

        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 isteği hazırlanıyor
                With updateStockCommand.Parameters
                    .Clear()
                    .Add(New OdbcParameter("mvt1", mouvement))
                    .Add(New OdbcParameter("id", idArticle))
                    .Add(New OdbcParameter("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

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:

Image

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:

Image

Ş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:
<?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.ArticlesDaoPlainODBC, webarticles-dao">
        <constructor-arg index="0">
            <value>odbc-firebird-articles</value>
        </constructor-arg>
        <constructor-arg index="1">
            <value>SYSDBA</value>
        </constructor-arg>
        <constructor-arg index="2">
            <value>masterkey</value>
        </constructor-arg>
    </object>
</objects>

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:

Image

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:

Image

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:

<?xml version="1.0" encoding="iso-8859-1" ?>
<configuration>
    <configSections>
        <sectionGroup name="spring">
            <section name="context" type="Spring.Context.Support.ContextHandler, Spring.Core" />
            <section name="objects" type="Spring.Context.Support.DefaultSectionHandler, Spring.Core" />
        </sectionGroup>
    </configSections>
    <spring>
        <context type="Spring.Context.Support.XmlApplicationContext, Spring.Core">
            <resource uri="config://spring/objects" />
        </context>
        <objects>
            <object id="articlesDao" type="istia.st.articles.dao.ArticlesDaoPlainODBC, webarticles-dao">
                <constructor-arg index="0">
                    <value>odbc-firebird-articles</value>
                </constructor-arg>
                <constructor-arg index="1">
                    <value>SYSDBA</value>
                </constructor-arg>
                <constructor-arg index="2">
                    <value>masterkey</value>
                </constructor-arg>
            </object>
            <object id="articlesDomain" type="istia.st.articles.domain.AchatsArticles, webarticles-domain">
                <constructor-arg index="0">
                    <ref object="articlesDao" />
                </constructor-arg>
            </object>
        </objects>
    </spring>
    <appSettings>
        <add key="urlMain" value="/webarticles/main.aspx" />
        <add key="urlInfos" value="vues/infos.aspx" />
        <add key="urlErreurs" value="vues/erreurs.aspx" />
        <add key="urlListe" value="vues/liste.aspx" />
        <add key="urlPanier" value="vues/panier.aspx" />
        <add key="urlPanierVide" value="vues/paniervide.aspx" />
    </appSettings>
</configuration>

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:

Image

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:

Image

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

Image

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

Image

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:

Image

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:

Image

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:
<?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.ArticlesDaoSqlServer, webarticles-dao">
        <constructor-arg index="0">
            <value>portable1_tahe\msde140405</value>
        </constructor-arg>
        <constructor-arg index="1">
            <value>dbarticles</value>
        </constructor-arg>
        <constructor-arg index="2">
            <value>admarticles</value>
        </constructor-arg>
        <constructor-arg index="3">
            <value>mdparticles</value>
        </constructor-arg>
    </object>
</objects>

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:

Image

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:

Image

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:
<?xml version="1.0" encoding="iso-8859-1" ?>
<configuration>
    <configSections>
        <sectionGroup name="spring">
            <section name="context" type="Spring.Context.Support.ContextHandler, Spring.Core" />
            <section name="objects" type="Spring.Context.Support.DefaultSectionHandler, Spring.Core" />
        </sectionGroup>
    </configSections>
    <spring>
        <context type="Spring.Context.Support.XmlApplicationContext, Spring.Core">
            <resource uri="config://spring/objects" />
        </context>
        <objects>
<objects>
    <object id="articlesdao" type="istia.st.articles.dao.ArticlesDaoSqlServer, webarticles-dao">
        <constructor-arg index="0">
            <value>portable1_tahe\msde140405</value>
        </constructor-arg>
        <constructor-arg index="1">
            <value>dbarticles</value>
        </constructor-arg>
        <constructor-arg index="2">
            <value>admarticles</value>
        </constructor-arg>
        <constructor-arg index="3">
            <value>mdparticles</value>
        </constructor-arg>
    </object>
            <object id="articlesDomain" type="istia.st.articles.domain.AchatsArticles, webarticles-domain">
                <constructor-arg index="0">
                    <ref object="articlesDao" />
                </constructor-arg>
            </object>
        </objects>
    </spring>
    <appSettings>
        <add key="urlMain" value="/webarticles/main.aspx" />
        <add key="urlInfos" value="vues/infos.aspx" />
        <add key="urlErreurs" value="vues/erreurs.aspx" />
        <add key="urlListe" value="vues/liste.aspx" />
        <add key="urlPanier" value="vues/panier.aspx" />
        <add key="urlPanierVide" value="vues/paniervide.aspx" />
    </appSettings>
</configuration>

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:

Image

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:

Image

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

Image

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

Image

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

Image

  • [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:

Image

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

Image

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

Image

  • [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:

Image

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

Image

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

Image

  • 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:
Provider=Microsoft.Jet.OLEDB.4.0;Data Source=D:\data\serge\databases\access\articles\articles.mdb;

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:

Image

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:
<?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.ArticlesDaoOleDb, webarticles-dao">
        <constructor-arg index="0">
            <value>Provider=Microsoft.Jet.OLEDB.4.0;Data Source=D:\data\serge\databases\access\articles\articles.mdb;</value>
        </constructor-arg>
    </object>
</objects>

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:

Image

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:

Image

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:
<?xml version="1.0" encoding="iso-8859-1" ?>
<configuration>
    <configSections>
        <sectionGroup name="spring">
            <section name="context" type="Spring.Context.Support.ContextHandler, Spring.Core" />
            <section name="objects" type="Spring.Context.Support.DefaultSectionHandler, Spring.Core" />
        </sectionGroup>
    </configSections>
    <spring>
        <context type="Spring.Context.Support.XmlApplicationContext, Spring.Core">
            <resource uri="config://spring/objects" />
        </context>
        <objects>
            <object id="articlesDao" type="istia.st.articles.dao.ArticlesDaoOleDb, webarticles-dao">
                <constructor-arg index="0">
                    <value>Provider=Microsoft.Jet.OLEDB.4.0;Data Source=D:\data\serge\databases\access\articles\articles.mdb;</value>
                </constructor-arg>
            </object>
            <object id="articlesDomain" type="istia.st.articles.domain.AchatsArticles, webarticles-domain">
                <constructor-arg index="0">
                    <ref object="articlesDao" />
                </constructor-arg>
            </object>
        </objects>
    </spring>
    <appSettings>
        <add key="urlMain" value="/webarticles/main.aspx" />
        <add key="urlInfos" value="vues/infos.aspx" />
        <add key="urlErreurs" value="vues/erreurs.aspx" />
        <add key="urlListe" value="vues/liste.aspx" />
        <add key="urlPanier" value="vues/panier.aspx" />
        <add key="urlPanierVide" value="vues/paniervide.aspx" />
    </appSettings>
</configuration>

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:

Image

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:

Image

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

Image

[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):

Image

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

Image

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:

Image

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:
<?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.ArticlesDaoFirebirdProvider, webarticles-dao">
        <constructor-arg index="0">
            <value>localhost</value>
        </constructor-arg>
        <constructor-arg index="1">
            <value>D:\data\serge\databases\firebird\dbarticles2.gdb</value>
        </constructor-arg>
        <constructor-arg index="2">
            <value>sysdba</value>
        </constructor-arg>
        <constructor-arg index="3">
            <value>masterkey</value>
        </constructor-arg>
    </object>
</objects>

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

Image

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:

Image

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:

Image

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:

Image

  • [runtime] içinde, [web.config] yapılandırma dosyası, yeni uygulama sınıfını dikkate alan bir dosyayla değiştirilir:
<?xml version="1.0" encoding="iso-8859-1" ?>
<configuration>
    <configSections>
        <sectionGroup name="spring">
            <section name="context" type="Spring.Context.Support.ContextHandler, Spring.Core" />
            <section name="objects" type="Spring.Context.Support.DefaultSectionHandler, Spring.Core" />
        </sectionGroup>
    </configSections>
    <spring>
        <context type="Spring.Context.Support.XmlApplicationContext, Spring.Core">
            <resource uri="config://spring/objects" />
        </context>
        <objects>
            <object id="articlesDao" type="istia.st.articles.dao.ArticlesDaoFirebirdProvider, webarticles-dao">
                <constructor-arg index="0">
                    <value>localhost</value>
                </constructor-arg>
                <constructor-arg index="1">
                    <value>D:\data\serge\databases\firebird\dbarticles2.gdb</value>
                </constructor-arg>
                <constructor-arg index="2">
                    <value>sysdba</value>
                </constructor-arg>
                <constructor-arg index="3">
                    <value>masterkey</value>
                </constructor-arg>
            </object>
            <object id="articlesDomain" type="istia.st.articles.domain.AchatsArticles, webarticles-domain">
                <constructor-arg index="0">
                    <ref object="articlesDao" />
                </constructor-arg>
            </object>
        </objects>
    </spring>
    <appSettings>
        <add key="urlMain" value="/webarticles/main.aspx" />
        <add key="urlInfos" value="vues/infos.aspx" />
        <add key="urlErreurs" value="vues/erreurs.aspx" />
        <add key="urlListe" value="vues/liste.aspx" />
        <add key="urlPanier" value="vues/panier.aspx" />
        <add key="urlPanierVide" value="vues/paniervide.aspx" />
    </appSettings>
</configuration>

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:

Image

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

Image

Şimdi [ARTICLES] tablosunun içeriğini kontrol edelim:

Image

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

Image

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

Image

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:

  1. providers.config: verilere erişmek için kullanılacak sınıf kütüphanelerini tanımlar
  2. sqlmap.config: kurulacak bağlantının özelliklerini tanımlar
  3. 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:

<?xml version="1.0" encoding="utf-8" ?> 

<providers>
    <clear/>
    <provider 
        name="Odbc1.1" 
        enabled="true" 
        assemblyName="System.Data, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" 
        connectionClass="System.Data.Odbc.OdbcConnection" 
        commandClass="System.Data.Odbc.OdbcCommand" 
        parameterClass="System.Data.Odbc.OdbcParameter" 
        parameterDbTypeClass="System.Data.Odbc.OdbcType" 
        parameterDbTypeProperty="OdbcType" 
        dataAdapterClass="System.Data.Odbc.OdbcDataAdapter" 
        commandBuilderClass="System.Data.Odbc.OdbcCommandBuilder" 
        usePositionalParameters = "true"
        useParameterPrefixInSql = "false"
        useParameterPrefixInParameter = "false"
        parameterPrefix = "@"
    />
</providers>

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:
insert into ARTICLES(id,nom,prix,stockactuel,stockminimum) values (?,?,?,?,?)

ya da

insert into ARTICLES(id,nom,prix,stockactuel,stockminimum) values (@id,@nom,@prix,@sa,@sm)

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

<?xml version="1.0" encoding="utf-8" ?>
<sqlMapConfig xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="Schemas\SqlMapConfig.xsd">
    <properties resource="properties.xml"/>
    <settings>
        <setting useStatementNamespaces="false" />
        <setting cacheModelsEnabled="false" />
    </settings>
     <!-- ==== veri kaynağı ========= -->    
    <database>
        <provider name="${provider}"/>
        <dataSource name="sqlmaparticles"  connectionString="${connectionString}"/>
        <transactionManager type="ADO/SWC" />
    </database>
    <sqlMaps>
        <sqlMap resource="articles.xml" />
    </sqlMaps>
</sqlMapConfig>

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ı:
1
2
3
4
5
<?xml version="1.0" encoding="utf-8" ?>
<settings>
    <add key="provider" value="Odbc1.1" />
    <add key="connectionString" value="DSN=odbc-firebird-articles;UID=SYSDBA;PASSWORD=masterkey" />
</settings>
  1. satır - [provider] anahtarı tanımlanmıştır. Değeri, [providers.config] dosyasında kullanılacak <provider> etiketinin adıdır

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

<?xml version="1.0" encoding="iso-8859-1" ?>
<sqlMap namespace="Articles" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="SqlMap.xsd">
     <!-- resultMap -->
    <resultMaps>
        <resultMap id="article" class="istia.st.articles.dao.Article">
            <result property="id" column="ID" />
            <result property="nom" column="NOM" />
            <result property="prix" column="PRIX" />
            <result property="stockactuel" column="STOCKACTUEL" />
            <result property="stockminimum" column="STOCKMINIMUM" />
        </resultMap>
    </resultMaps>
     <!-- SQL sorguları -->
    <statements>
         <!-- tüm makalelerin alınması -->
        <select id="getAllArticles" resultMap="article">
                select ID,NOM,PRIX,STOCKACTUEL,STOCKMINIMUM FROM ARTICLES
            </select> 
         <!-- tüm makalelerin silinmesi-->
        <delete id="clearAllArticles">
                delete from ARTICLES
            </delete> 
         <!-- bir ürünün eklenmesi -->
        <insert id="insertArticle" parameterClass="istia.st.articles.dao.Article">
                insert into ARTICLES (id, nom, prix,stockactuel, stockminimum) values
                ( #(id#, #ad#, #fiyat#, #mevcutstok#, #minimumstok#)
            </insert>
         <!-- bir ürünün silinmesi -->
        <delete id="deleteArticle" parameterClass="int">
                delete FROM ARTICLES where ID= #değer#
            </delete>
         <!-- ürün düzenleme -->
        <update id="modifyArticle" parameterClass="istia.st.articles.dao.Article">
                update ARTICLES set NOM= #isim# ,PRIX= #fiyat# ,STOCKACTUEL= #mevcutstok# ,STOCKMINIMUM= #minimumstok# where ID= #id#
            </update>
         <!-- belirli bir ürünün aranması -->
        <select id="getArticleById" resultMap="article" parameterClass="int">
                select ID, NOM, PRIX,    STOCKACTUEL, STOCKMINIMUM FROM ARTICLES where ID= #değer#
            </select>
         <!-- bir ürünün stokunda değişiklik -->
        <update id="changerStockArticle" parameterClass="Hashtable">
                update ARTICLES set STOCKACTUEL=(STOCKACTUEL + #hareket#) where ID=#id# and ((STOCKACTUEL + #hareket#) >=0)
      </update>
    </statements>
</sqlMap>

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:

Image

SqlMap sınıflarını kullanan uygulamalar, [IBatisNet.DataMapper] ad alanını içe aktarmalıdır:

Imports IBatisNet.DataMapper

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:

        Dim mappeur As SqlMapper = Mapper.Instance

SqlMap [getAllArticles] komutunu çalıştırmak için şu kod yazılır:

                    dim articles as IList=mappeur.QueryForList("getAllArticles", Nothing)
  • [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:
<resultMap id="article" class="istia.st.articles.dao.Article">

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:

dim unArticle as Article=CType(mappeur.QueryForObject("getArticleById", idArticle), Article)
  • [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:

                    mappeur.Insert("insertArticle", unArticle)
  • [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:

                    dim nbArticles as Integer=mappeur.Delete("deleteArticle", idArticle)
  • [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:

                    dim nbArticles as Integer=mappeur.Delete("clearAllArticles", nothing)

SqlMap [modifyArticle] komutunu çalıştırmak için şunu yazın:

                    dim nbArticles as Integer=mappeur.Update("modifyArticle", unArticle)
  • [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:

Image

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:
1
2
3
4
5
6
7
8
<?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.ArticlesDaoSqlMap, webarticles-dao"/>
</objects>

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:

Image

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:

Image

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:

Image

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:

  1. [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.
  2. SqlMap'in .NET sürümünde hata var
  3. Firebird'ün ODBC sürücüsünde hata var
  4. ...

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:

....
Namespace istia.st.articles.dao

    Public Class ArticlesDaoSqlMap
        Implements IArticlesDao

         ' özel alanlar
        Dim mappeur As SqlMapper = Mapper.Instance

         ' tüm ürünlerin listesi
        Public Function getAllArticles() As IList Implements IArticlesDao.getAllArticles
...
        End Function

         ' ürün ekleme
        Public Function ajouteArticle(ByVal unArticle As Article) As Integer Implements IArticlesDao.ajouteArticle
...
        End Function

         ' ürün silme
        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
                    If ex.GetType.Equals(GetType(IBatisNet.Common.Exceptions.ConcurrentException)) Then Return 0
                    Throw New Exception("Erreur lors de la suppression de l'article d'id [" + idArticle.ToString + "] : [" + ex.ToString + "]")
                End Try
            End SyncLock
        End Function

         ' bir makaleyi düzenleme
        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
                    If ex.GetType.Equals(GetType(IBatisNet.Common.Exceptions.ConcurrentException)) Then Return 0
                    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
...
        End Function

         ' tüm ürünlerin silinmesi
        Public Sub clearAllArticles() Implements IArticlesDao.clearAllArticles
....
        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: Stoku 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
                    If ex.GetType.Equals(GetType(IBatisNet.Common.Exceptions.ConcurrentException)) Then Return 0
                    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

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:

Image

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:

Image

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

Image

  • [runtime] içinde, [web.config] yapılandırma dosyası, yeni uygulama sınıfını dikkate alan bir dosyayla değiştirilir:
<?xml version="1.0" encoding="iso-8859-1" ?>
<configuration>
    <configSections>
        <sectionGroup name="spring">
            <section name="context" type="Spring.Context.Support.ContextHandler, Spring.Core" />
            <section name="objects" type="Spring.Context.Support.DefaultSectionHandler, Spring.Core" />
        </sectionGroup>
    </configSections>
    <spring>
        <context type="Spring.Context.Support.XmlApplicationContext, Spring.Core">
            <resource uri="config://spring/objects" />
        </context>
        <objects>
            <object id="articlesDao" type="istia.st.articles.dao.ArticlesDaoSqlMap, webarticles-dao"/>
            <object id="articlesDomain" type="istia.st.articles.domain.AchatsArticles, webarticles-domain">
                <constructor-arg index="0">
                    <ref object="articlesDao" />
                </constructor-arg>
            </object>
        </objects>
    </spring>
    <appSettings>
        <add key="urlMain" value="/webarticles/main.aspx" />
        <add key="urlInfos" value="vues/infos.aspx" />
        <add key="urlErreurs" value="vues/erreurs.aspx" />
        <add key="urlListe" value="vues/liste.aspx" />
        <add key="urlPanier" value="vues/panier.aspx" />
        <add key="urlPanierVide" value="vues/paniervide.aspx" />
    </appSettings>
</configuration>

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:

Image

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

Image

Şimdi [ARTICLES] tablosunun içeriğini kontrol edelim:

Image

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

Image

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

Image

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

Image

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

Image

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

Image

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

Image

[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:
    1. ODBC kaynaklarına erişim için .NET erişim sınıflarını kullanarak
    2. SQL Server kaynaklarına erişim sınıfları .NET'i kullanarak
    3. .NET erişim sınıflarını kullanarak OleDb kaynaklarına erişmek
    4. 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.