Makale Özeti

Sanıyorum tüm uygulama geliştiriciler, birbiri ile ilgili birden çok değeri temsil edecek veri türlerine gereksinim duyduğumuzda farklı veri türleri kullanmak ve işleri gereğinden fazla karmaşıklaştırmak yerine bu işi tek bir veri türü ile çözmeyi tercih eder. SQL Server 2005’te bunu yapmak son derece basit ve SQL Server 2000’e göre çok daha sağlıklı bir hal almış durumda.

Makale

Sanıyorum tüm uygulama geliştiriciler, birbiri ile ilgili birden çok değeri temsil edecek veri türlerine gereksinim duyduğumuzda farklı veri türleri kullanmak ve işleri gereğinden fazla karmaşıklaştırmak yerine bu işi tek bir veri türü ile çözmeyi tercih eder. SQL Server 2005’te bunu yapmak son derece basit ve SQL Server 2000’e göre çok daha sağlıklı bir hal almış durumda.

SQL Server 2005’te .NET CLR entegrasyonunun en önemli avantajlarının başında, veri türlerimizi istediğimiz .NET dili ile geliştirebiliyor olmamız. Bu makalede SQL Server 2005’te kullanıcı tanımlı veri türü oluşturmayı ve kullanımını ele alıyor olacağız.

Oluşturacağımız kullanıcı tanımlı veri türü bir satış otomasyonunda kullanılacak ve ürünlere ait ayrı iki sütunda saklanan fiziksel ve kayıtlı stok oranlarını tek bir sütunda birleştirmemizi sağlayacak.

İlk olarak kullanıcı tanımlı veri türümüzü tanımlayacağımız bir assembly oluşturacağız. Bu örnekte C# dilini kullanıyor olacağız ancak tercihe bağlı olarak diğer .NET dillerini de kullanabiliyoruz. Assembly’mizi oluşturmak için Visual Studio 2005’i açarak “Database” proje şablonlarından “User-Defined Type” şablonunu seçiyoruz. Kod ekranı açıldığında kullanıcı tanımlı türümüzü tanımlamak için aşağıdaki kodları yazıyoruz.

 
[Serializable]
[Microsoft.SqlServer.Server.SqlUserDefinedType(Format.Native)]
public struct ItemStock : INullable   
{
   public override string ToString()
   {
      return "";
   }
 
   public bool IsNull
   {
      get
      {
         return m_Null;
      }
   }
   public static ItemStock  Null
   {
      get
      {
         ItemStock
      
          h = new ItemStock ();
         h.m_Null = true;
         return h;
      }
   }
   public static ItemStock Parse(SqlString   s)
   {
      if (s.IsNull)
         return Null;
      ItemStock 
       u = new ItemStock ();
      return u;
   }
}
 

Kodlarımızı adım adım açıklayalım;

[Serializable]
Bu ifade kullanıcı tanımlı veri türümüzün serialize edilebileceğini belirtiyor. 

[Microsoft.SqlServer.Server.SqlUserDefinedType(Format.Native)]
Bu kullanıcı tanımlı veri türleri için gerekli bir özniteliktir. Format özelliği serialization formatını belirtir. Burada üç seçeneğimiz mevcuttur. Native, UnKnown, UserDefined. Bu öznitelik IsByteOrdered, IsFixedLength, MaxByteSize, Name ve ValidationMethodName parametreleri ile de belirtilebilir.

Format.Native
Bu SQL Server tarafından kullanılan ve en hızlı işlem yapan native binary serialization metodudur. Bu özellik sadece sabit uzunluklu veri türlerinde uygulanabilmektedir. Bu tür seçildiğinde MaxByteSize parametresi kullanılamamaktadır.

Format.UserDefined
Bu referans türleri tarafından kullanılır. Eğer bu özellik seçilirse, serialization, IbinarySerialization arayüzü implement edilerek bizim tarafımızdan yapılmak durumundadır.

INullable
INullable arayüzü kullanıcı tanımlı türün, boş değerleri kabul edebilmesini sağlar. INullable arayüzünün IsNull özelliği de implement edilmelidir.

Statik Null Metodu
Bu metod kullanıcı tanımlı türün kendisini dönecek şekilde implement edilmelidir.

Statik Parse Metodu
Bu statik metod kullanıcı tanımlı türün bir string değerden dönüştürülebilmesini sağlar.

ToString()
Bu kullanıcı tanımlı türün vitrual ToString metodunu override ederek kullanıcı tanımlı türün metinsel hale dönüştürülmesini sağlar.

Temel konuları ele aldığımıza göre kullanıcı tanımlı türümüzü yeniden gözden geçirebiliriz.

[Serializable]
[Microsoft.SqlServer.Server.SqlUserDefinedType(Format.Native)]
public struct ItemStock : INullable
{
        //bu üç değişken fiziksel ve kayıtlı stoğumuzun değerlerini
        //saklayacak ve  kullanıcı tanımlı türün değerinin boş olup
        //olmadığını gösterecek
        private int _physicalStock;
        private int _systemStock;
        private bool _isNull;
 
        // INullable readonly özelliği.
        public bool IsNull { get { return _isNull; } }
 
        //Bu metod null değerli kullanıcı tanımlı tür döner
        public static ItemStock Null
        {
               get
               {
                       ItemStock itemStock = new ItemStock();
                       itemStock._isNull = true;
                       return itemStock;
               }
        }
 
        //metinsel verinin kullanıcı tanımlı türe dönüşümü
        //eğer değer boşsa geriye boş kullanıcı tanımlı tür döner
        //eğer değer boş değilse doğrulanır ve yeni bir kullanıcı tanımlı
        //tür oluşturulur.
        public static ItemStock Parse(SqlString value)
        {
               if (value.IsNull)
                       return ItemStock.Null;
 
               ItemStock itemStock = new ItemStock();
               try
               {
                       string[] values = value.ToString().Split('|');
                       itemStock._physicalStock = Convert.ToInt32(values[0]);
                       itemStock._systemStock = Convert.ToInt32(values[1]);
                       itemStock._isNull = false;
                       
                       return itemStock;
               }
               catch (Exception exception)
               {
                       throw exception;
               }
        }
 
        //Kullanıcı tanımlı türün metinsel formata dönüşümü
        public override string ToString()
        {
               if (this.IsNull)
                       return "NULL";
               else
                       return this._physicalStock + " | " + this._systemStock;
        }
 
        //Fiziksel stoğu dönen readonly özellik
        public int PhysicalStock { get { return this._physicalStock; } }
 
        // Kayıtlı stoğu dönen readonly özellik
        public int SystemStock { get { return this._systemStock; } }
 
        //Kayıtlı ve fiziksel stok arasındaki farkı dönen readonly özellik
        public int Difference { get { return _physicalStock - _physicalStock;}}
}

Gördüğünüz gibi oldukça basit bir kod ile her durumu karşıladık ve üç yeni özellik tanımladık. Oluşturduğumuz kullanıcı tanımlı türün kullanımını ilerleyen bölümlerde göreceğiz ancak önce bu türü SQL Server 2005’e kaydetmeliyiz.

Bunun için Microsoft SQL Server Management Studio’yu çalıştırarak New Query butonunu tıklıyoruz. Kullanıcı tanımlı türü kaydetmek istediğimiz veritabanını seçerek aşağıdaki kodu yazıyoruz.

CREATE ASSEMBLY SQLServerUDTs
FROM '{AssemblyDizini}\SQLServerUDTs.dll'

Bu kodu çalıştırdıktan sonra oluşturduğumuz assemblye dayanan veri türünü oluşturmak için aşağıdaki kodu yazarak çalıştırıyoruz.

CREATE TYPE ItemStock EXTERNAL NAME SQLServerUDTs.ItemStock

Bu kodu çalıştırdığımızda ItemStock adlı kullanıcı tanımlı tür artık kullanılabilir hale geliyor.

Aşağıdaki kod ise oluşturduğumuz kullanıcı tanımlı veri türünü kullanan bir tablo oluşturarak işlemler gerçekleştirmektedir.

CREATE TABLE Items
(Id int IDENTITY(1,1) PRIMARY KEY,
[Name] varchar(100) NOT NULL,
InStock ItemStock NULL)
 
INSERT INTO Items ([Name], InStock) VALUES ('Yemek Masası 1', '0|0')
INSERT INTO Items ([Name], InStock) VALUES ('Yemek Masası 2', NULL)
INSERT INTO Items ([Name], InStock) VALUES ('Yemek Masası 3', NULL)
INSERT INTO Items ([Name], InStock) VALUES ('Yemek Masası 4', NULL)
--aşağıdaki ifade bir exception oluşmasına neden olacaktır
INSERT INTO Items ([Name], InStock) VALUES ('Yemek Masası 4', 'p|s')

Şu anda tablomuz örnek verilerle birlikte kullanıma hazır durumda.

-- Tablodaki tüm sütunları seç
SELECT Id, [Name], InStock.ToString(), 
        InStock.PhysicalStock, InStock.SystemStock
FROM Items
 
-- Kayıtların güncellenmesi
UPDATE Items
        SET InStock = '1860|1860'
WHERE Id = 3
UPDATE Items
        SET InStock = '138|156'
WHERE Id = 4
 
-- koşullar
SELECT Id, InStock.Difference
FROM Items
WHERE InStock.PhysicalStock < InStock.SystemStock

Gördüğünüz gibi SQL Server 2005'in .NET entegrasyonu, işleri çok daha kolay hale getiriyor. Özellikle alışık olduğumuz .NET dilini kullanabilmemiz kullanıcı tanımlı türler, stored procedure ve kullanıcı tanımlı fonksiyonlar gibi yapıların çok daha hızlı geliştirilebilmesini sağlıyor.