Sayfalar

24 Ağustos 2012 Cuma

SQL Server 2005+ Üzerinde CLR Assembly Entegrasyonu

Veritabanı bağımlı sistemler geliştirirken bazen performans için bazen de güvenlik için keşke şu metodu Sql Server üzerinden çağırabilseydim dediğimiz zamanlar olur. Örneğin; bir masaüstü uygulaması geliştirilirken genel geçer yöntem, uygulamaların istemci, veri tabanının da bir sunucu şeklinde tasarlanmasıdır. Böyle bir durumda ayrıca bir sunucu uygulaması yazma maliyetinden kurtulmuş olunur, veri tabanı sunucusunun da istemci sunucusu olarak kullanılması sağlanmış olur. Ancak bu sunucunun kabiliyetleri veri tabanı sunucusunun kabiliyetleri ile sınırlı olacaktır.

Öyle bir zaman olur ki tüm veri işlemlerinize cevap verebilen bir sunucu, basit bir algoritma için destek vermeyebilir; Örneğin, veri tabanının bulunduğu makine üzerindeki birtakım bilgilere erişemezsiniz.

Böyle bir durumda çözüm için ilk ve sık kullanılan yöntem ana makineye istemciyi dinleyecek ayrı bir sunucu Windows servisi yazmaktadır. Bu da veri tabanı sunucusu yanında ayrıca çalışacağından ve TCP/IP bağlantısı gibi ek bir bağlantı için fazladan port ve bellek kullanacaktır. Bunun yanında istemci uygulamaya da veri tabanı sunucusuna yapacağı bağlantıya ek olarak yeni yazılacak olan sunucuya bağlanıp metot çağırmak gibi ek bir iş daha verilmiş olacaktır.

Tüm geliştiriciler böyle bir noktada “keşke şu metodu veri tabanı üzerinden çağırabilseydim” diyecektir. Peki, bu mümkün mü? Eğer CLR desteği veren bir veri tabanı sistemi kullanıyorsanız bu mümkün! Nasıl mı yapılıyor? CLR ile derlenen bir kütüphaneyi alıp veri tabanı içine gömüyorsunuz, yazdığınız metotları SQL cümlesi ile çağırıyorsunuz, hepsi bu.

Microsoft, SQL Server 2005’ten itibaren CLR desteği vermeye başladı. Oracle gibi diğer büyük firmalar da CLR desteği vermektedir. Bu makalede bu işlemin SQL Server 2008 üzerinde nasıl yapılacağını anlatacağım.

Öncelikle veri tabanını CLR kodları çalıştırmaya hazırlamamız gerekiyor. Bunu yapmak için kurulumda kapalı olan CLR çalıştırma özelliğini açmamız gerekiyor:

sp_configure 'clr enable', 1
GO

RECONFIGURE
GO

Bunun sonucunda aşağıdaki mesaj dönerse bu işlem başarıyla yapılmış demektir.

Configuration option 'clr enabled' changed from 0 to 1. Run the RECONFIGURE statement to install.

Şimdi Visual Studio içerisinde bir C# Class Library projesi açıp örneğin SqlAgent adını verelim. Bu projedeki Class1.cs dosyasının adı Agent olacak şekilde yeniden adlandıralım. Bu projenin Target Framework’ü ile SQL Server sürümünün desteklediği sürüm aynı olmalıdır. Örneğin MS Sql Server 2008, CLR için .NET 4.0 desteklememektedir; .NET 3.0 kullanabilirsiniz.

Bunun ardından sıra içini SQL Server üzerinde çalışmasını istediğimiz 2 adet metot ile doldurmaya geldi. Bu metotları biri Stored Procedure (SP) olarak, diğeri User-Defined Function (UDF) olarak çağırmak isteyeceğimizi düşünelim. İki adet sayının ortalamasını döndüren Mean adında bir UDF ve verdiğiniz ismi "My name is {0}" şeklinde bir mesaj olarak parametre üzerinden döndüren bir SP yazalım.

using System.Data.SqlTypes;
using Microsoft.SqlServer.Server;

namespace SqlAgent
{
     public class Agent
     {
          [SqlFunction]
          public static SqlDouble Mean(SqlDouble a, SqlDouble b)
          {
               return (a + b) / 2;
          }

          [SqlProcedure]
          public static void ShowMyName(SqlString name, out SqlString returnValue)
          {
               returnValue = new SqlString(string.Format("Your name is {0}", name.Value));
          }
     }
}

Bu yazdığımız yeni metotları daha sonra sarmalayan birer SP ve UDF yazacağız. Metotlar arasındaki mappingi üstlerindeki SqlFunction ve SqlProcedure attribute’ları ile belirtiyoruz. Bu attribute’lar Microsoft.SqlServer.Server ad uzayı altında bulunmaktadır. Bu noktada bir diğer uyarım CLR etkin metotların sadece System.Int32, int ve void dışında değer döndürmeyeceğinden dolayı SqlProcedure olarak işaretlenecek olan metotların bu tiplerden biri olması gerektiğidir. Bir diğer nokta da veri tiplerine dikkat ederseniz string, double gibi CLR veri tipleri yerine System.Data.SqlTypes ad uzayı içindeki SqlDouble, SqlString gibi veri tiplerini kullanmış olmaktır.

Bu projeyi derlediğimizde oluşan SqlAgent.dll dosyası Sql Server içine gömeceğimiz Assemby dosyasının ta kendisinden başka bir şey değildir.

Şimdi sıra en can alıcı ve sıkıntılı noktaya, yani Assembly dosyasını Sql Server içine gömme işlemine geldi. Bunu yapabilmek için veri tabanında Owner haklarına sahip olmanız veya Local System Admin veya Server Admin olmanız gerekmektedir. Ayrıca Assembly Registration işlemini gerçekleştirecek olan kullanıcının UNSAFE hakkına sahip olması gerekmektedir; Aksi takdirde kayıt işlemini gerçekleştiremeyecektir. Kayıttan önce veri tabanının TRUSTWORTHY özelliğini de açmamız gerekmektedir.

Test adında bir veri tabanımız olduğunu düşünürsek Sql Server içinde aşağıdaki komut ile bu özellik açılacaktır:

ALTER DATABASE Test SET TRUSTWORTHY ON
GO

Kayıt yapmak için gereken komut ise

USE [Test]
GO

CREATE ASSEMBLY SqlAgentAssembly
AUTHORIZATION dbo
FROM 'D:\SqlAgent.dll'
WITH PERMISSION_SET = UNSAFE
GO

Burada bir önemli husus da yazdığınız kütüphane başka kütüphaneleri kullanmakta ise öncelikle o kütüphanelerin buraya eklenmesi gerekliliğidir. Örneğin System.Management sınıfını kullanıyorsanız, aşağıdaki gibi onları da hiyerarşik öncelikle eklemeniz gerekir.

USE [Test]
GO

CREATE ASSEMBLY Management
AUTHORIZATION dbo
FROM 'C:\Windows\Microsoft.NET\Framework\v2.0.50727\System.Management.dll'
WITH PERMISSION_SET = UNSAFE
GO

Not:
  • Ekleme işleminde problemler yaşıyorsanız dosyayı GAC içine koymak bir çözüm olabilir.
  • Not 2: Eğer bu kayıt işini başarıyla tamamlayabilmişseniz, SqlAgent.dll dosyası ile işiniz bitmiş demektir. Dosyayı uçurabilirsiniz!
Son olarak yapacağımız işlem bu CLR metotların birer SQL nesneleri ile sarmalanması olacaktır. ShowMyName adlı SqlProcedure olarak işaretlenen metodu SQL içerisinden çağırmak için aşağıdaki SP’yi tanımlamak lazım gelir:

USE [Test]
GO

CREATE PROCEDURE sp_ShowMyName @name NVARCHAR(50), @returnValue NVARCHAR(MAX) OUTPUT
AS EXTERNAL NAME SqlAgentAssembly.[SqlAgent.Agent].ShowMyName
GO

Mean adlı SqlFunction olarak işaretlenen metot için ise aşağıdaki UDF tanımlanmalıdır:

USE [Test]
GO

CREATE FUNCTION udf_Mean(@a FLOAT, @b FLOAT)
RETURNS FLOAT
AS EXTERNAL NAME SqlAgentAssembly.[SqlAgent.Agent].Mean
GO

Bunları başarı ile yapabildiysek Sql Server Object Explorer’da aşağıdaki görüntüyü alabiliyor olmalıyız.
 O halde ne mutludur bize ki artık SQL cümlesi ile bunları çağırabiliriz! Bu SQL nesnelerini çağırmak için aşağıdaki sorguları yazalım:

USE [Test]
GO

DECLARE @returnValue nvarchar(max)
EXECUTE [Test].[dbo].[sp_ShowMyName] 'Onur', @returnValue OUTPUT

SELECT @returnValue AS [What's My Name];
GO

SELECT dbo.udf_Mean(2, 10) AS [Mean of 2 and 10 is]
GO

Aldığımız yanıt aşağıdaki gibidir, işlem başarılıdır...



Böylece bu yöntem sayesinde veri tabanının yapılabileceklerini hayal gücünüz ile sınırlamış oluyorsunuz.

Hiç yorum yok:

Yorum Gönder