Makale Özeti

SQL server 2000 ile web tabanlı bir uygulamanın temelleri...

Makale

Turgut HASPOLAT
turguthaspolat@hotmail.com
21.01.2002



Merhabalar,
Bu yazımda sizlere, bir web tabanlı uygulamanın veritabanı ve XML özelliklerinden faydalalanarak çok amaçlı kullanımına yönelik tasarlanmasını anlatmaya calışaçağım. Bu amaçla SQL Server 2000 de kullanabileceğiniz bazı fonksiyon ve özelliklerin kullanımına yönelik daha önce üzerinde çalıştığım web tabanlı uygulamadan örnekleme yaparak bir anlatım yolu izleyeceğim. Bu yazı, ASP, ActiveX DLL ve SQL Server konularında yeterli seviyede bilgi birikimine sahip olanlara hitap edecektir.

Web Tabanlı Uygulamaların işlevliği arttıkça kontrolleri de artmaktadır. Bu ise çok fazla kontrol kodu demektir. Server-Side kodlar, Client-Side kontroller, grafik tasarım, DHTML derken ASP sayfamız içinden çıkılmaz bir hale dönüşebilir. Özellikle uygulamaya yeni modül eklentilerinde, baştaki tasarımınıza bağlı olarak yama yapabilir ya da herşeye yeniden başlayabilirsiniz. Öte yandan uygulamanızın efektif kullanımına yönelik performansı da düşünmek zorundasınız. Bu amaçla bileşenler oluşturabilir ya da mevcut bileşenlerden faydalanabilirsiniz; ayrıca grafik tasarım ve arayüz standartını da belirlemeniz gerekir. Tüm katmanların aynı yerde farklı kodlanması ve kontrolü, standartlaşma ve birlikte çalışabilirlik unsurları da dikkate alındığında, sistem tasarımcılarını üzerinde çok fazla düşündürmektedir.

Bu anlatımda ki temel amacım bir web tabanlı uygulamanın mümkün olduğunca çok yönlü, çok amaçlı ve kullanışlı (generic) bir yapıda olmasını sağlamak için tespit ettiğim arayışlardır. Bildiğiniz gibi veritabanına bağlı uygulamalarda yoğunlukla veri girişi, düzenleme, sorgulama ve silme gibi işlemler yapılmaktadır. Bunun için veritabanından bir tablonun kayıtlarını kullanıcı ekranına listeleriz ve gerekli butonlar vasıtası ile interaktif olarak kullanıcıdan istek bekleriz. Standart veritabanı işlemleri dışında uygulamadan yapılması istenen özel durumlarda kod yazarak kontrol oluşturmamız gerekir. Örneğin veritabanından gelen kayıt listesinin kullanıcının istediği alana (column) göre sıralama (sort) işleminin artan yada azalan şekilde yapılabilmesi.

Bu aşamada uygulamanın sistem mimarisinde üç ana unsur ortaya çıkmaktadır. Sistem tasarımı, veritabanı tasarımı ve arayüz tasarımı. Kullanıcı-Uygulama iletişimini sağlayan arayüz standartı büyük önem kazanmaktadır. Sistem mimari tasarımında kullanıcıya anlaşılır (user friendly) arayüzler tasarlamak ve standartları belirlemek, varsa belirlenmiş standartlara uymak, oluşturacağımız generic yapıda en önemli unsur olacaktır. Kullanıcının isteklerini bildireceği arayüz tasarımında standarları belirlemek ve yerleşik bir ortamda (XML gibi) tutmak uygulamanın geliştirilmesi ve uygulamalar arası entegrasyon açısından fayda sağlayacaktır. Tasarım aşamasında ihtiyaçlar ve iş gereçlerini planlayarak arayüz standart oluşumuna yansıtmak gerekir. Büyük bir ivme ile yaygınlaşan XML teknolojilerini bu amaçla kullanım gerekliliği aşikardır. Bunun yanısıra arka planda server-side kodlarla veriitabanı ile yapılan iletişimlerde XML büyük efektiflik sağlayacaktır.

Bir dinamik ASP sayfasının oluşumunda, arayüz standarlarını belirleyeceğimiz iş akışını veritabanında saklayabiliriz. Bunu açacak olursak veritabanında ki nesneler ve özelliklerine göre asp sayfasının nasıl davranacağını belirlemek ve kullanıcının rahat davranabilmesi sağlayacak arayüz tasarımı oluşturmak için gerekli iş adımlarını veritabanına gömmek olarak tanımlayabiliriz. Üzerinde düşünüldüğünde bu generic yapıyı, veritabanı özelliklerini kullanarak oluşturabileceğimizi görebiliriz. Böylece karmaşık uygulamalarda bile iyi bir veritabanı ve arayüz tasarımı ile ölçeklenebilir, genişletilebilir ve performans kazançlı web tabanlı uygulamalar geliştirebiliriz. Bunun için mevcut araçların ( XML, Database ) özelliklerini iyi bilmemiz ve nerde nasıl kullanacabileceğimiz tespit etmemiz gerekir.

Sizlere bu yazıdan itibaren web tabanlı uygulamalarda çok amaçlı ve kullanışlı (generic - aslında bu kelimeyi tam olarak tanımlayamadım) yapı oluşturmada izlediğim yöntemleri aktarmaya çalışacağım. Bunun için özellikle SQL Server 2000 ve XML teknolojilerini nasıl kullanabileceğimizi aktarmaya çalışacağım. Aşağıdaki konular daha iyi anlaşılması için örnek tablo ve arayüz uygulama üzerinden anlatılmaya çalışılmıştır.



SQL Server 2000 da Sütun (column) Description Değerinin Alınması
Microsoft SQL Server 2000deki SQL Server Enterprise Manager içinde herhangi bir tablonun Table Design penceresini açtığınızda, pencerenin alt yarısında seçili sütunun (column) bazı özellikleri listelenir. Bunlardan birsi de Description (Tanım) özelliğidir. Enterprise Manager Description özelliği bir genişletilmiş özelliktir (extended property).

Bu genişletilmiş özellikleri bazı veritabanı nesnelerinin bilgilerini saklamak için kullanabiliriz. Ben burda sizlere tablolar (tables) ve sütünların (columns) Description genişletilmiş özellik tanımlanmasını ve bu bilgileri ASP sayfası içinden nasıl elde edileceğini (retrieve) anlatmaya çalışacağım.

SQL Sever 2000de genişletilmiş özellikleri almak için bir sistem fonksiyonu tanımlanmıştır. Bu fonksiyon fn_listextendedproperty() sistem fonksiyonudur. Bu fonksiyonun sözdizimi (syntax) aşağıdaki gibidir.

Syntax
fn_listextendedproperty (
{ default | [ @name = ] property_name | NULL }
, { default | [ @level0type = ] level0_object_type | NULL }
, { default | [ @level0name = ] level0_object_name | NULL }
, { default | [ @level1type = ] level1_object_type | NULL }
, { default | [ @level1name = ] level1_object_name | NULL }
, { default | [ @level2type = ] level2_object_type | NULL }
, { default | [ @level2name = ] level2_object_name | NULL }
)


Aşağıdaki sözdizimi veritabanındaki table nesnesinden T1 tablosunun tüm sütunlarının (column) genişletilmiş özellikleri listeler. Eğer column nesnesinden sonra default yerine tabloda herhangi bir sütun adını verirsek o sütunun genişletilmiş özellikleri listelenecekti.

SELECT * FROM ::fn_listextendedproperty (NULL, user, dbo, table, T1, column, default)

Veritabanımızda belediye bilgilerini tutan il_t_belediye adında bir tablomuz olsun. Tablomuzun Table Design penceresi yandaki şekilde olduğu gibidir. Gördüğünüz gibi belediyead sütununun Description özelliğne Belediye Adı değeri atanmıştır.
Aşağıdaki SQL cümleciğinde tablo adını il_t_belediye ve sütun adını belediyead olarak girersek;
SQL Server Query Analyzerda çalıştırdığımızda aldığımız sonuç nesne tipinin sütun (COLUMN) olduğunu , nesne isminin belediyead ve değerinin (value) ise Belediye Adı olduğunu görebiliriz.


Yukardaki örnek SQL cümleciğinde bir sütünun Description genişletilmiş özelliğinin nasıl alınacağını gördünüz.
Şimdi ise veritabanında depolanan bu bilgiye ASP sayfasından nasıl erişebileceğimize bakalım.

Öncelikle bu fonksiyonu dinamik bir yapıda kullancağımızı düşünürsek, veritabanına erişen bir bileşen (ActiveX DLL) haline getirmek bir çok açıdan daha uygun olacaktır. Bu amaçla Visual Basic ortamında geliştirdiğim FileldDesc() fonksiyonu aşağıdaki gibidir. FileldDesc() fonksiyonuna değişken olarak gelecek sTableName ve sFieldName değerlerini strSQL cümleciğinde veritabanından sorgulayarak veritabanında gelecek olan sütun Description değerini (value) döndürür.
( Not : kodda görmüş olduğunuz OpenRS ve CloseRS birer Private fonksiyon olup ADOnun Connection ve Recordset nesnelerini kullanarak veritabanına bağlantı ve kayıt seti oluşturma işlevlerini yapmaktadır.)


Public Function FieldDesc(ByVal strConn As Variant, ByVal sTableName As Variant, &_                           ByVal sFieldName As Variant) As Variant
  Dim sFieldNameAs String
  OpenRS strConn
  strSQL = "SELECT * FROM ::fn_listextendedproperty (NULL, user, dbo, table, &_            " & sTableName & ", column, " & sFieldName & ")"
  rs.CursorLocation = adUseServer
  rs.Open strSQL, conn, adOpenStatic
  If Not (rs.BOF or rs.EOF) Then
    sFieldName = rs("value")
  End If
  FieldDesc = sFieldName
  CloseRS
End Function


Son olarak oluşturduğumuz bileşeni (ActiveX DLL) ASP sayfamızdan nasıl çağıracağımızı görelim. Öncelikle Server nesnesinin CreateObject metodunu kullanarak oluşturduğumuz ActiveX bileşeninden bir örnekleme (instance) nesne oluşturmamız gerekir. Aşağıda gördünüz gibi ActiveX DLLmizin adı SQL2kObj.dll, Class Module adı da DBDesc dir. ActiveX bileşenimizden objSQL2kDB isimli bir nesne örnekledik.

<% Set objSQL2kDB = Server.CreateObject("SQL2kObj.DBDesc") %>


Aşağıdaki örnek arayüzde gördünüz üzere; il_t_belediye tablosunun tüm sutün (column) Description değerlerini dinamik bir yapıda yazdırmak istediğimizde objSQL2kDB nesnemizin FieldDesc metodu değerlerini (attributes) aşağıdaki gibi tanımlayabiliriz. Aşağıdaki kodu bir döngü içinde kullanırsak, tablonun tüm sütun adlarını fonksiyona gönderebilir ve fonksiyonda veritabanından Description değerlerini bize geri döndürerek istediğimiz alana yazdırmış oluruz.

    <% strConn = "Veritabanına bağlantı stringi" %>
<TD><%Response.Write objSQL2kDB.FieldDesc(strConn, "il_t_belediye", fld.name)%></TD>



Yukardaki arayüzde gördüğünüz üzere kayıları veritabanından listelerken sütun adlarını da daha önce veritabanında tanımladığımız sütun Description genişletimiş özelliklerden alarak dinamik olarak yazdırabiliriz.



SQL Server 2000 sysforeignkeys Sistem Tablosunun Kullanımı
Bu örnekte, veritabanımızda il_t_belediye ve il_t_il tabloları var ve bu tablolar arasında bir ilişki (Relationship) kurulmuştur. Şekilden de anlaşılacağı üzere il_t_il tablosu (Primary key table) ilkod alanı ile il_t_belediye tablosu (Foreign key table) ilkod alanları arasında birden çoğa (one to many) bir ilişki vardır. Yani Belediye Bilgileri tablosundaki ilkod sütunu İller tablosundaki bir sütuna referans eder.
Burada size anlatmaya çalışağım konu Belediye Bilgileri kayıtlarını ekrana yazdırıken, il_t_belediye tablosunda ilkod (Foreign Key) sütunundaki il kodu değeri yerine, referans eden İller Tablosunda ilkod (Primary Key) değeri ile eşleştirerek karşılık gelen ilad sütunundaki İl Adı değerini İller Tablosundan çekerek yazdırmak.

Bir tabloda bulunan foreign key bir sütunun (column) veritabanında referans eden Primary Key sütuna ulaşmak için veritabanında ki sistem tablolarından sysforeignkeys sistem tablosundan faydalanacağız. SQL Server Query Analyzerda aşağıdaki SQL cümleciğin WHERE koşuluna foreign key tablo adını yazarsak bize referans eden primary key tablo ve sütun adını getirecektir.




Bu bilgileri ASP sayfalarımızda dinamik olarak kullanabilmek için yukardaki SQL cümlesini kullanarak daha önce oluşturduğumuz SQL2kObj.dll ActiveX bileşenimize bir fonksiyon daha ekleyelim.
Bu fonksiyona foreign key sütun adını (sFieldName), değerini (sFieldValue), refereans eden tablodaki kaçıncı sütunu yazdırmak istediğimizi (nWhichField) ve foreign key tablo adını gönderiyoruz.

Kodu inceleyecek olursak; pkSQL cümlesinin WHERE koşulunda foreign key tablo adını (sTableName) göndererek sysforeignkeys sistem tablosundan referans eden primary key tablo adı/adlarını ve sutün adı/adlarını alıyoruz. Foregin key tablomuz veritabanında birden fazla tabloya referans edebileceğini düşünerek oluşacak kayıt setinde bir döngü ile column_name ile foreign key (sFieldName) alanımız arasında eşitlik arıyoruz. Kayıt setinde foregin key (sFieldName) sütununa karşılık gelen primary key tablo adını tespit ettikten sonra SELECT cümlesi ile bizim foregin key sutünumuzun değeri ile primary key tablodaki karşılık gelen sütunun değerini alıyoruz. Eğer değer dönerse daha önceden karar verdiğimiz (sWhichField) primary key tablo sütununun değerini fonksiyona atıyoruz. Dolayısı ile bize bu fonsiyon bize dinamik olarak primary tablosunu bularak bu tabladon istediğimiz stüun değerini yazdırmamızı sağlıyor.

Burda fonsiyonu generic bir yapıda kurduğumuzdan fonsiyona foreign key tablo adı verilmediği takdirde değer dönmeyeceğinden bir flag tutuyoruz ve fonsiyon sonucunda gönderilen sütun değerini (sFieldValue) tekrar fonksiyona atıyoruz.

Public Function FindPkFld(ByVal strConn As Variant, ByVal sFieldName As Variant, &_                           ByVal sFieldValue As Variant, ByVal nWhichField As Variant,&_                           ByVal sTableName As Variant) As Variant

  Dim Flag As Boolean
  Dim sPKey As String
  Dim pkSQL As String

  Dim consulta As ADODB.Command
  Dim rsconsulta As ADODB.Recordset

  OpenRS strConn
  Flag =
False

  pkSQL = "SELECT object_name(fkeyid) as FKey_Table, "
  pkSQL = pkSQL + "col_name(fkeyid, fkey) as column_name, "
  pkSQL = pkSQL + "object_name(rkeyid) as PKey_Table, "
  pkSQL = pkSQL + "col_name(rkeyid, rkey) as referenced_column_name "
  pkSQL = pkSQL + "FROM sysforeignkeys "
  pkSQL = pkSQL + "WHERE object_name(fkeyid) = " & sTableName & ""

  rs.CursorLocation = adUseServer
  rs.Open pkSQL, conn, adOpenStatic


  Do While Not rs.EOF
    If rs("column_name") = sFieldName Then
      Set consulta = New ADODB.Command
      Set consulta.ActiveConnection = conn
      consulta.CommandText = "SELECT * FROM " & rs("referenced_table_name") &_
      " WHERE " & rs("referenced_column_name") & "=" & sFieldValue

      Set rsconsulta = consulta.Execute
      If Not (rsconsulta.EOF And rsconsulta.EOF) Then
        sPKey = rsconsulta(nWhichField)
      End If
      Set rsconsulta = Nothing
      Set consulta = Nothing
      Flag = True
      FindPkFld = sPKey
    End If
    rs.MoveNext
  Loop
    If Flag = False Then
       FindPkFld = sFieldValue
    End If
  CloseRS
End Function


Konuyu şekildeki İller tablosu ve Belediye Bilgileri tablosundaki değerlerle açıklayacak olursak;
Aşağıdaki şekilde arayüzünü görmüş olduğunuz Belediye Bilgileri modülünde kayıtları ekrana yazdırırken, il_t_belediye tablosunun ilkod sütununda ki değerler il kodlarıdır. Yani şekilde görülen İli alanındaki ZONGULDAK değerleri aslında il_t_belediye tablosunda 67 olarak tutulmaktadır. Biz bu alana 67 değerini değilde bu sutüna referans eden primary key tablosundaki ilkod alanının değerini eşleştirerek eşitlik sağlandığı satırdaki ilad sütununun değerini yazdırmak istiyoruz. Bu durumda il_t_belediye tablosundaki 67 değeri il_t_il tablasundaki 67 değeri ile eşleştiriliyor ve bu satırdaki karşılık gelen ilad değeri yani ZONGULDAK değeri il_t_il tablosundan alınarak yazdırılıyor.



Aşağıdaki server-side scriptte gördüğünüz üzere objSQL2kDB nesnemizin FindPkFld metodu değerlerini (attributes) örnekteki gibi tanımlayabiliriz. Aşağıdaki kodu bir döngü içinde kullanırsak, tablonun foreign key tüm sütun adları fonksiyona gönderilir ve fonksiyon sistem tablosunu kullanarak karşılık gelen primary key tablodan istediğimiz sütunun değerini bize geri döndürür.
Aşağıdaki script, foreign key sütun adı, değer, ve karşılık gelen primary key tablosunun 1 nci (yani ikinci satırını - kayıt setinde satırlar 0dan başlar) sütun değerini TD tagi arasına yazdırır.

<%strConn = "Veritabanına bağlantı stringi" %>
<TD>
<%
Response.WriteobjSQL2kDB.FindPkFld(strConn,fld.name,rs(fld.name),1,"il_t_belediye")%>
<
/TD>



Gradient Filter
Aşağıdaki arayüz de üzerinde Belediye Bilgileri yazılı olan ve Windows işletim sistemlerinden bildiğiniz renk geçişli program başlık barı aslında Microsoft® Internet Explorer 5.5 veya sonraki sürümlerinde kullanılabilecek bir renk geçişi filtresidir. (Gradient Filter) . Arayüzlerde görmüş olduğunuz filtre kodunu CSS dosyanıza ekleyerek yada tag içinde stil (style) tanımlayarak kullanabilirsiniz. Benim kullandığım TD tag için CSS style filtre kodu aşağıdaki gibidir.


  TD.tdGradient
  {
    FILTER: progid:DXImageTransform.Microsoft.gradient(GradientType=1, startColorstr=#000080, endColorstr=#6099FC)
  }


GradientType 0
(sıfır) veya 1 (bir) değerlerini alır. 0 olması renk geçişinin yukarda aşağıya, 1 olması renk geçişinin soldan sağa doğru olmasını sağlar.
startColorstr ve endColorstr anlaşılacağı üzere başlangıç ve bitiş renk değerlerini veriyorsunuz. Bu örnekte koyu laciverten açık tona doğru renk geçişi var.

Filtreler ile ilgli daha fazla bilgiyi aşağıdaki adresten bulabilirsiniz
http://msdn.microsoft.com/workshop/author/filter/filters.asp#Scripting_Filters

Unutmayın bu özellik ancak Microsoft® Internet Explorer 5.5 veya sonraki sürümlerinde kullanılabilir.




Sizlere SQL Server 2000 fonsiyon ve nesnelerini kullanarak web tabanlı bir uygulamada generic bir yapı nasıl oluşturabileceğimizi iki örnekle anlatmaya çalıştım. Bundan sonraki yazılarımda yine veritabanı ve XML özelliklerinden faydalanarak yazımın başında anlatmaya çalıştığım yapının oluşumuna yönelik düşüncelerimi aktarmaya çalışacağım.