Makale Özeti

Yukon ile birlikte duyurulan CLR desteği ile ilgili makalelerimin sonuncusu olan User Defined Type konusu ile birlikte, Yukon da .Net ile yapabileceğiniz ve çok fazla kullanılan nesneleri incelemeyi bitirdik. Bu makalede Kullanıcı Tanımlı Tip oluşturup, bunun nasıl kullanılacağını inceleceksiniz...

Makale

CLR Destekli User Defined Type Yazmak

SQL Server 2005 in CLR ile çalışmabilmesi sonucu, CLR Destekli diller ile Stored Procedure ler, Trigger lar Kullanıcı Tanımlı Fonksiyonlar ve Kullanıcı Tanımlı tipler oluşturabilirsiniz. Sizin için önemli olan tarafı, daha önceki makalelerdede değindiğimiz gibi, farklı bir dil, farklı bir platform öğrenmek zorunda olmadan kullanıdığınız .Net dili ile bu yapıları oluşturabilmenizdi, Stored Procedure ve Trigger ları inceledik, şimdi sırada ise Kullanıcı tanımlı tipler var.

SQL Server 2000 de kullanıcı tanımlı tipler i oluştururken varolan tiplerden faydalanıp bir tip oluşturabiliyorduk, ancak şimdi tamamen .Net yapılarını kullanarak bir Structure ın SQL Server 2005 de kullanılacak bir tip olmasını sağlayabilirsiniz. Bu işlemi yaparkende tamamen .Net platformunu, .Net yetenekleri ve kolaylıklarını kullanabilirsiniz.

Daha önceki makalelerdede belirttiğim gibi benim kullandığım platform, SQL Server 2005 CTP (SQL Server 9.0.1116) ve Visual Studio 2005 Beta 2 ve bu platform da işlerinizi çok daha kolaylaştıracak ve hızlandıracak yapılar var. Örneklerimizi yapmak için, Visual Studio 2005 i açıp, Create Project diyoruz daha sonra Visual Basic altından Database i oradanda uygulama tipi olarak SQL Server Project i seçiyoruz ve isim olarakta YazGelistirOrnek giriyoruz, Tamam a bastığımızda karşımıza Add Database Reference ekranı geliyor, bu ekranda hangi veri kaynağına bağlanmak istediğimiz soruluyor, buradan varolan bir veritabanını seçebilirsiniz yada Add New Reference butonuna basıp yeni bir veri kaynağı ekleyebilirsiniz, biz örneklerimiz için daha önceden hazırlamış olduğumuz YazGelistirOrnek isimli veritabanını kullanacağız. Yeni oluşturduğumuz projeye sağtuş ile tıklayıp Add menüsünden User-Defined Type ı seçiyoruz isim olarakta Nokta veriyoruz. Visual Studio 2005 tarafından bize bir şablon tip tanımlaması oluşturuluyor, şablon aşağıdaki şekilde,

Imports System

Imports System.Data

Imports System.Data.Sql

Imports System.Data.SqlTypes

Imports Microsoft.SqlServer.Server

 

<Serializable()> _

<Microsoft.SqlServer.Server.SqlUserDefinedType(Format.Native)> _

Public Structure Nokta

    Implements INullable

 

    Public Overrides Function ToString() As String

        ' Put your code here

        Return ""

    End Function

 

    Public ReadOnly Property IsNull() As Boolean Implements INullable.IsNull

        Get

            ' Put your code here

            Return m_Null

        End Get

    End Property

 

    Public Shared ReadOnly Property Null As Nokta

        Get

            Dim h As Nokta = New Nokta

            h.m_Null = True

            Return h

        End Get

    End Property

 

    Public Shared Function Parse(ByVal s As SqlString) As Nokta

        If s.IsNull Then

            Return Null

        End If

 

        Dim u As Nokta = New Nokta

        ' Put your code here

        Return u

    End Function

 

    ' This is a place-holder method

    Public Function Method1() As String

        ' Put your code here

        Return "Hello"

    End Function

 

    ' This is a place-holder static method

    Public Shared Function Method2() As SqlString

        ' Put your code here

        Return New SqlString("Hello")

    End Function

 

    ' This is a place-holder field member

    Public var1 As Integer

    ' Private member

    Private m_Null As Boolean

End Structure

Dikkat ederseniz, ihtiyacım olabilecek bütün yapıları Visual Studio 2005 şablon olarak bana oluşturdu, ben sadece kendi ihtiyacım olabilecek ekstra yapıları ekleyip, bunların kullanılmasını sağlayacağım. Visual Studio 2005 in benim için hazırladığı yapıları inceleyelim, daha önceki makalelerden farklı olarak bu sefer benim için bir Structure oluşturuluyor. Yani benim tipim bir class değil Structure, ismi ise dosyaya isim verirken yazdığım Nokta. Namespace ler için daha önceden yazdığım makaleleri inceleyebilirsiniz, Attribute lerde Serializable ve SqlUserDefinedType Attribute leri mevcut, SqlUserDefinedType a parametre olarak verilen Format, Seriileştirme işleminin nasıl yapılacağını anlatıyor, Structure mıza, INullable Interface i Imlement edilmiş durumda, Structure lar value tipleri olduklarından, Null tutamazlar, INullable Interfacesi Null değer tutulmasını sağlar (Yazılım Mimarisi kategorisindeki Nullable Tipler ile ilgili makalemden daha detaylı bilgi edinebilirsiniz) birisi Public diğeri Private olmak üzere iki tane değişken tanımlanmış durumda, private olan değişken, Structure ın Null mı değilmi bilgisini tutuyor, diğeri ise sizin yazacağınız Tipin değerini null olarak yollayacak yapı. SQL Server da Allow Null gibi bi özellik olduğundan, yazdığınız Tipin Null değer alabilmesi çok önemli. İki tane ReadOnly property mevcut, bu property ler Null değerler ile ilgili bir tanesi Structure ın tuttuğu değer Null mı diye bakıyor, diğeri ise Null değeri atanmış, bir Nokta döndürüyor. Bununla birlikte 4 tanede Fonksiyon var, bu fonksiyonlardan özellikle iki tanesi işimize çok yarayacak, bunların isimleri ToString ve Parse, bunula birlikte iki tanede örnek metot mevcut, bu örnek metotlar sadece size şablon olarak verilmiş durumda, şimdi kendi yazıcağımız tipe bakalım, aşağıdaki kodları inceleyin lütfen.

<Serializable()> _

<Microsoft.SqlServer.Server.SqlUserDefinedType(Format.Native)> _

Public Structure Nokta

    Implements INullable

 

    Public Property proX() As Integer

        Get

            Return Me.memX

        End Get

        Set(ByVal value As Integer)

            Me.memX = value

        End Set

    End Property

 

    Public Property proY() As Integer

        Get

            Return Me.memY

        End Get

        Set(ByVal value As Integer)

            Me.memY = value

        End Set

    End Property

 

    Public Overrides Function ToString() As String

        Return Me.memX & "," & Me.memY

    End Function

 

    Public ReadOnly Property IsNull() As Boolean Implements INullable.IsNull

        Get

            Return m_Null

        End Get

    End Property

 

    Public Shared ReadOnly Property Null() As Nokta

        Get

            Dim h As Nokta = New Nokta

            h.m_Null = True

            Return h

        End Get

    End Property

 

    Public Shared Function Parse(ByVal s As SqlString) As Nokta

        If s.IsNull Then

            Return Null

        End If

 

        Dim u As Nokta = New Nokta

        Dim varKoordinat() As String = s.ToString().Split(",".ToCharArray())

        u.proX = Int32.Parse(varKoordinat(0))

        u.proY = Int32.Parse(varKoordinat(1))

        Return u

    End Function

 

    Public Function funSifiraUzaklik() As SqlDouble

        Return CType(Math.Sqrt(Me.memX ^ 2 + Me.memY ^ 2), SqlDouble)

    End Function

 

    Private memX As Integer

    Private memY As Integer

    Private m_Null As Boolean

End Structure

Benim Nokta tipimde özellikle grafiksel uygulamalar için kullanılabilecek bir yapı mevcut, yani kullanıcı değer olarak Nokta tipini girebilir, böylece String ile uğraşmak yerine direk Nokta olarak tanımladığı tipi kullanabilir, yazdığım kodda Null olabilmek ile ilgili kodları bıraktım, çünkü o bölüm zaten düzgün olarak çalışıyor. Bunun yanında iki tane değişken ekledim, memX ve memY değişkenleri, bu değişkenler dışarıdan değer alabilsinler diye iki tane property tanımladım, ve kullanıcı örneğin INSERT işlemini yaparken, virgül “,” ile ayrılmış veriyi girdiğinde, Parse() Metodunu otomatik olarak çalışıp, bunları benim Structure ım daki bu tanımladığım değişkenlere atayacak, peki ya okuduğu zaman, okuduğu zaman ise otomatik olarak ToString() Metodu çalışacak ve benim Structure ım içindeki değişkenleri okuyup, onları Virgul ile birleştirip String olarak geri yollayacak. Bunun yanında, yaptığım işlemleri biraz daha pekiştirmek için bu noktanın “0,0” yani merkeze olan uzaklığını bulması amacıyla funSifiraUzaklik() isimli bir metot yazdım, eğer isterse kullanıcı ekstra hiçbir işlem yapmadan, bu noktaların sıfıra olan uzaklıklarınıda bulabilecek. Şimdi yazdığımız bu kodu nasıl kullanacağımızı inceleyelim, kodunuzu Build edin ve daha sonra Deploy edin. SQL Server Management Studio da aşağıdaki şekilde bir görünüm elde etmiş olmalısınız.

Şimdi bir tablo oluşturalım, bu tabloda da tanımladığımız Nokta tipini kullanalım, Tabloyu çok basit, aşağıdaki şekilde oluşturabilirsiniz.

CREATE TABLE [dbo].[NoktaTablosu](

      [NoktaId] [tinyint] IDENTITY(1,1) NOT NULL,

      [NoktaKoor] [dbo].[Nokta] NULL,

 CONSTRAINT [PK_NoktaTablosu] PRIMARY KEY CLUSTERED

(

      [NoktaId] ASC

) ON [PRIMARY]

) ON [PRIMARY]

Gördüğünüz gibi, NoktaKoor isimli sütun, Nokta tipinden tanımlanmış durumda, peki ben ekleme işlemini nasıl yapacağım, ilk iş olarak SQL Server Management Studio dan ekleyelim, Tabloya sağ tuş işe tıklayın ve Open Table a basın. İlk önce 3,5 koordinatını gireceğim, daha sonra ise hatalı girişe izin vermediğini göstermek için 3:6 şeklinde gireceğim ve şu hatayı alacağım,

Peki ya INSERT cümleciği ile nasıl eklemeliydim,

INSERT INTO NoktaTablosu VALUES('3,7')

Yukarıdada belirttiğim gibi, Parse() Metodu benim için atamanın yapıldığı yer, bu metot SqlString alıyor ve geriye Nokta döndürüyor. Bende bir String verdim ve Parse() Metodundan sonra geriye X ve Y koordinatları atanmış bir Nokta döndü.

Şimdi bu eklediğimiz noktaları nasıl çekeceğimize, kısacası SELECT cümleciğimize bakalım, yine yukarıda belirttiğim gibi eğer SELECT yapacaksak, ToString() metodu çalışacak bu Metot ta geriye String döndürüyor, SELECT cümleciğinizi şöyle yazabilirsiniz,

SELECT NoktaId,NoktaKoor.ToString() FROM NoktaTablosu

Son olarakta eklediğim ekstra metodu inceleyelim, funSifiraUzaklik() Metodunu, bu Metot Koorinatları buluyor ve geriye SqlDouble döndürüyor, böylece küsüratlı verileride tutabiliyorum, kullanımına bakalım,

SELECT NoktaKoor.funSifiraUzaklik() FROM NoktaTablosu

Dahada gelişmiş bir işlem yapabilirsiniz, örneğin tablomda kayıtlı olan bütün Noktaların sıfıra olan uzaklıklarının ortalmasını alabilirsiniz,

Bu makale SQL Serverdaki CLR ile birlikte gelen yeniliklerden biri olan User Defined Type ları inceledik. İstek, öneri ve eleştirileriniz için aşağıdaki mailimi kullanabilirsiniz.

Levent Cenk ÇAĞLAR

cenk.caglar@yazgelistir.com