آموزش SQL Server

آموزش تخصصی برنامه نویسی

آموزش SQL Server

آموزش تخصصی برنامه نویسی

استفاده از CLR Integration در SQL Server 2005 (قسمت سوم)

اگر فرض کنیم که متد GetStrings() تحت عنوان یک TVF با همان نام ثبت شده است، آنگاه مثلا زیر، قطعه ای از T-SQL از یک stored procedure است که از این TVF برای بیرون کشیدن (extract) line items ، در شکل جدولی استفاده می کند.
CREATE PROCEDURE Insert_Order @cust_id int, @lineitems nvarchar(8000)
AS
BEGIN
...
INSERT LineItems
SELECT * FROM dbo.GetStrings(@lineitems)
...
END

کدام را استفاده کنیم؟

تصمیم در مورد اینکه یک stored procedure را در ترکیب با SqlPipe- چه غیر مستقیم در T-SQL و چه مستقیم د ر یک CLR routine- یا یک table-valued function استفاده کنیم، بستگی به فاکتورهای زیادی دارد که باید مد نظر قرار گیرند، که شامل composability requirements، منبع داده ها، نیاز به اثرات جانبی، و typing requirements برای خروجی است. به ترتیب هر کدام از آنها را مورد بحث قرار می دهیم.

Composability Requirements

شاید استفاده دوباره یا تغییر (manipulation) خروجی بدست آمده درون یک TVF یا یک stored procedure، مطلوب باشد. Table-valued functions از نقطه نظر composability، پرکاربردتر هستند، مثلاً نوع بازگشت (return type) یک TVF، یک rowset نسبی است که در هر جاییکه چنین ساختاری مجاز است، قابل استفاده است. مخصوصاً، دربخش FROM در عبارت SELECT، قابل استفاده است، و چنین خروجیی می توانند از composability of SELECT در sub-queryها، عبارات INSERT...SELECT، جدولهای مشتق شده، و جدول عبارات استفاده کنند.

از سوی دیگر، ، می توان stored procedureها را فقط به عنوان بخشی از ترکیب INSERT...EXEC، از درون T-SQL language، compose کرد، که به خروجی بدست آمده اجازه ذخیره شدن در یک جدول دایم یا موقت را می دهد. عملیات INSERT، یک کپی واقعی از داده ها را ارائه می کند که احتمالاً روی performance تاثیر گذار خواهد بود.

اگر composability و استفاده مجدد از خروجی درون سرور یک نیاز باشند، TVFها جایگزینهای بهتری هستند. اگر خروجی بدست آمده فقط نیاز به stream شدن به client یا middle-tier داشته باشند، هر دو روش منطقی است.

منبع داده ها (Source of the Data)

منبع داده هایی که بازگردانده می شود، فاکتور مهم دیگری در انتخاب بین پیاده سازی بر اساس T-SQL یا CLR است. خروجی را میتوان هم از طریق خواندن source در local instance با استفاده از ADO.NET provider یا از طریق یک source خارج از SQL Server، بدست آورد. در منابع خارجی، پیاده سازی بر پایه CLR، انتخاب بهتری از T-SQL است، به علت داشتن سهولتی که logic accessing the external data، توسط آن انجام می شود.

در صورت بدست آوردن خروجی بر اساس یک query که با استفاده از ADO.NET provider روی local instance اجرا شده، یک stored procedure، معمولاً یک query را اجرا می کند، از طریق خروجی تکرار می شود، و بعضی از عملیات ها را روی rowها، قبل از بازگرداندن از طریق یک SqlPipe، انجام می دهد.

با یک TVF ، برنامه نویسان می توانند یک شی data reader را خوانده و در یک کلکسیون در حافظه بارگذاری کنند. اما، SQL Server 2005، به requestها اجازه نمی دهد تا زمانی که یک table-valued function باز می گردد، pending بمانند؛ هر query که از طریق ADO.NET provider اجرا شده است، باید کاملاً اجرا شوند و خروجی باید به طور کامل قبل از اینکه function body بتواند بازگردد، consume شوند. اگر عبارت بازگشت (return statement)، هنگامی که SqlDataReader operationها در ADO.NET provider، معلق (pending) است، اجرا شود، یک error ممکن است روی دهد. این بدین معناست که در اکثر مواردی که داده ها از local database instance بازگردانده می شوند، نمی توان داده ها را از طریق یک CLR TVF، stream کرد. اگر فاکتورهای دیگر از قبیل composability، مستلزم نوشته شدن به عنوان یک TVF باشد، شاید نوشتن آن در T-SQL تنها آپشن باشد. در غیر این صورت، استفاده از یک stored procedure مدیریت شده که از SqlPipe استفاده می کند، ممکن است.

در مواردی که در آنها خروجی قرار است از درون یک stored procedure بر اساس داده ها از local instance، بدست آید، استفاده از APIهای SendResults فقط در مواردی معنا دارد که خروجی نیاز به مقداری اصلاح یا تغییر رویه ای (procedural modification or manipulation) دارد.

عملیاتهایی (operation) با اثرات جانبی (Side-Effect)

بطور کلی، operationهایی که دارای side-effect هستند- operationهایی که حالت database، از قبیل عبارات DML، یا transaction operationها، را تغییر می دهند- از functionهایی (مثلاً functionهای table-valued) که تعریف کاربر است، منع می شوند؛ اما شاید این operationها مطلوب باشند. مثلاً ممکن است کسی بخواهد یک SAVEPOINT transaction را set کند، یا یک operation اجرا کند، و در صورت روی دادن error، آن را به SAVEPOINT، rollback کند.

با فرض اینکه functionهایی که کاربر تعریف می کند، منع می شوند، چنین سناریویی فقط از طریق یک stored procedure قابل پیاده سازی است، و خروجی باید از طریق SqlPipe بازگردانده شوند. اما به یاد داشته باشید، به operationهایی با side-effect، اجازه اجرا شدن از طریق ADO.NET provider، زمانیکه SqlPipe مشغول فرستادن خروجی است، داده نمی شود. این operationها فقط قبل از اینکه خروجی شروع یا بعد از اینکه تکمیل شوند، مجاز هستند.

Typing و تعداد خروجی

توصیف خروجی بدست آمده از طریق یک CLR stored procedure توسط SqlPipe، با خروجی بدست آمده از یک CLR TVF متفاوت، و با همتایانشان در T-SQL یکسان هستند.

از سوی دیگر، یک stored procedure declaration، هیچ عبارتی در مورد خروجی بدست آمده – یا حتی آیا آنها را بدست می آورد- نمی سازد. ممکن است آسان بنظر آید، و گرچه مسلماً انعطاف (flexibility) بیشتری ایجاد می کند، ولی باید در نوشتن applicationهایی که stored procedureها را اجرا می کنند دقت بیشتری کرد، زیرا ممکن است است به طور دینامیکی شکل خروجی را دوباره تعریف کند. اما، اگر لازم باشد که schema برای خروجی در میان فراخوانی ها ()invocation متغیر باشند، باید از یک stored procedure استفاده کرد، زیرا فقط SqlPipe این انعطاف را در اختیار می گذارد.

در حقیقت، نوع داده های ضعیف خروجی ها تولید شده از طریق sqlpipe درون Stored Procedureها، فراتر از Schemaی یک خروجی واحد است که احتمال بازگشت چندین خروجی متغیر را دربر می گیرد. هم typeها و هم تعداد خروجی را می توان توسط stored procedure به طور دینامیکی تعیین کرد.

خلاصه

جدول زیر خلاصه ای از راهنماییهایی در مورد چگونگی تعیین اینکه آیا یک application ویژه باید در T-SQL یا CLR نوشته شود، و یا اینکه آیا یک stored procedure یا یک table-valued function باید استفاده شود، است.

 

خیر بله موقعیت
Procedure یا TVF TVF آیا Composability نیاز است؟

(accessing only local data) T-SQL TVF یا procedure

CLR TVF یا CLR procedure

منبع خارجی داه ها (در مقابل (accessing only local data
Procedure یا TVF Procedure آیا side-effect نیاز است؟
Procedure Procedure یا TVF results schema ثابت؟
Procedure یا TVF Procedure بیش از یک دسته خروجی
T-SQL TVF CLR TVF آیا قادر به stream کردن خروجی است؟

در اکثرجاهای این بخش، ارسال خروجی از طریق SqlPipe، به شدت با procedureها پیوند خورده است. گرچه SqlPipe و امکان بازگرداندن خروجی در بدنه CLR triggerها در دسترس هستند، اما این عمل به شدت نهی می شود، زیرا ممکن است به خروجی غیر منتظره ای برای issuing Data Manipulation Language یا عبارات Data Definition Language statements با triggerهایی که روی اشیاء هدف تعریف شده، منجر شود.

اجرای Aggregationهای سفارشی روی داده ها

سناریوهایی وجود دارند که ممکن است aggregation نیاز به اجرا شدن روی data داشته باشد، که شامل اجرای محاسبات آماری از قبیل یافتن میانگین ها، انحراف از معیار (standard deviation) و غیره است. اگر aggregation function مورد نظر، در داخل ساخته نشود، راههای زیادی برای اضافه کردن (add) functionality در SQL Server 2005 وجود دارد:

· نوشتن aggregation به عنوان یک aggregation تعریف شده توسط کاربر (UDA).

· نوشتن aggregation با استفاده از یک CLR stored procedure.

· استفاده از یک cursor جانبی سرور (server-side) در T-SQL.

بیایید این سه راه را در بافت (context) یک aggregation function ساده که محصول یک دسته از valueهای معین را محاسبه می کند، امتحان کنیم.

مثال: یک Product که به عنوان یک aggregate function تعریف شده توسط کاربر، پیاده سازی شده

در اینجا کدی برای این task آورده شده که به عنوان یک aggregate تعریف شده توسط کاربر نوشته شده. Logic محاسبه این محصول، وقتی که وارد می شود، در متد Accumulate() وجود دارد. متد Merge()، تعریف می کند اگر این دو aggregate ادغام شوند، چه اتفاقی می افتد.

در Visual Basic .NET:

Imports System
Imports System.Data.SqlTypes
Imports Microsoft.SqlServer.Server

<Serializable()> _
<SqlUserDefinedAggregate(Format.Native)> _
Public Structure ProductAgg

Private product As SqlInt32

Public Sub Init()
product = 1
End Sub

Public Sub Accumulate(ByVal value As SqlInt32)
product = product * value
End Sub

Public Sub Merge(ByVal group As ProductAgg)
product = product * group.product
End Sub

Public Function Terminate() As SqlInt32
Return product
End Function

End Structure

در C#:

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

[Serializable]
[SqlUserDefinedAggregate(Format.Native)]
public struct ProductAgg
{
private SqlInt32 product;

public void Init()
{
product = 1;
}

public void Accumulate(SqlInt32 value)
{
product = product * value;
}

public void Merge(ProductAgg group)
{
product = product * group.product;
}

public SqlInt32 Terminate()
{
return product;
}
}
 

بعد از اینکه این type، با SQL Server ساخته و ثبت شد، می توان آن را فقط به عنوان یک built-in aggregate از T-SQL استفاده کرد:

SELECT dbo.ProductAgg(intcol) 
FROM tbl
GROUP BY col
 

مثال: Product، به عنوان یک Stored Procedure مدیریت شده

یک stored procedure را می توان ایجاد کرد که روی data تکرار می شود تا محاسبه (computation) را اجرا کند. این تکرار با استفاده از کلاس SqlDataReader بدست می آید، همانطور که در پایین نشان داده شده.

در Visual Basic .NET:

 
Imports Microsoft.SqlServer.Server
Imports System.Data.SqlTypes
Imports System.Data.SqlClient

Partial Public Class StoredProcedures

<SqlProcedure()> _
Public Shared Sub VBProductProc(ByRef value As SqlInt32)

' The empty product is 1
value = 1

Using conn As New SqlConnection("context connection = true")
conn.Open()
Dim cmd As SqlCommand = New SqlCommand()
cmd.Connection = conn
cmd.CommandText = "SELECT intcolumn FROM tbl"
Dim r As SqlDataReader = cmd.ExecuteReader()
Using r
Do While r.Read()
value = value * r.GetSqlInt32(0)
Loop
End Using
conn.Close()
End Using
End Sub

End Class

در C#:


using Microsoft.SqlServer.Server;
using System.Data.SqlTypes;
using System.Data.SqlClient;
public partial class StoredProcedures
{
[SqlProcedure]
public static void ProductProc(out SqlInt32 value)
{
// Ensure that we write to value.
// Empty product is 1.
value = 1;

using (SqlConnection conn =
new SqlConnection("context connection = true"))
{
conn.Open();
SqlCommand cmd = new SqlCommand();
cmd.Connection = conn;
cmd.CommandText = "SELECT intcolumn FROM tbl";
SqlDataReader r = cmd.ExecuteReader();
using (r)
{
while (r.Read()) //skip to the next row
{
value *= r.GetSqlInt32(0);
}
}
}
}
}

می توان این را با استفاده از عبارت T-SQL EXEC فرا خواند:

 
 
EXEC Product @p OUTPU

مثال: Product به عنوان یک T-SQL Stored Procedure که از یک Cursor استفاده می کند

نهایتاً، می توان یک T-SQL stored procedure ایجاد کرد که یک query را اجرا و محاسبه را با استفاده از یک T-SQL cursor انجام می دهد تا data را تکرار کند.

T-SQL:

create procedure TSQL_ProductProc (@product int output)
as
begin
declare @sales int
declare c insensitive cursor for select intcolumn from tbl

set @product = 1

open c
fetch next from c into @sales

while @@FETCH_STATUS = 0
begin
set @product = @product * @sales
fetch next from c into @sales
end

close c
deallocate c
end
go

خلاصه

تصمیم گیری در مورد استفاده از یک UDA یا یکی از راه حلهای دیگر برای بدست آوردن خروجی به چند عامل بستگی دارد، که شامل composability requirements، مشخصه های aggregation algorithm، و نیاز به side-effect می شود.

در واقع، یک UDA، یک شی مستقل است که از هر T-SQL query، قابل استفاده است، عموماً در همان مکانی که یک system aggregate استفاده می شود. هیچ تصوری در مورد یک query که روی آن عمل می کند وجود ندارد. مثلاً، می توان آن را در view definitionها (اما نه در indexed viewها) و در sub-queryهای ترازویی (scalar) به شمار آورد.

می توان UDAها را قبل از کلمه ORDER BY در یک query ارزیابی کرد، پس هیچ تضمینی برای ترتیبی که valueها به aggregation function ارائه می شوند وجود ندارد. بنابراین، اگر aggregation algorithm باید valueها را به ترتیب خاصی consume کند، نمی توان از یک UDA استفاده کرد. یک UDA نیز دقیقاً valueهای کل یک گروه را consume می کند و یک value واحد باز می گرداند. اگر مشکل حل نشد، آنگاه باید از یک تکنیک دیگر استفاده کرد.

همچنین یک UDA، هیچ data access را اجرا نمی کند و هیچ side-effect ندارد؛ اگر هر یک از اینها لازم باشند، آنگاه باید از یک stored procedure استفاده کرد.

گرچه UDAها دارای محدودیتهایی هستند، اما احتمال دارد بهترین performance را از آپشنهای ارائه شده انجام دهند، پس aggregation عموماً باید از طریق یک UDA اجرا شود، مگر اینکه الزامات (requirement) دیگر مانع آن شوند.

Typeهای تعریف شده توسط کاربر

حالا به یکی از قدرتمندترین ویژگیهای SQL Server 2005 می رسیم که اغلب مورد سوء تفاهم قرار می گیرد. با Typeهای تعریف شده توسط کاربر (UDTها)، می توان scalar type system را در database، گسترش داد. و این، فراتر از تنها تعریف کردن alias برای یک system type است که در نسخه قبلی SQL Server دردسترس بود. تعریف یک UDT، به سادگی نوشتن یک کلاس در کد مدیریت شده، ایجاد یک اسمبلی، و سپس (register) ثبت کردن type در SQL Server با استفاده از عبارت CREATE TYPE است. مثال زیر، اسکلت یک کد است که شکل ساختاری یک UDT را نشان می دهد.

در Visual Basic .NET:

<Serializable()> _
<Microsoft.SqlServer.Server.SqlUserDefinedType(Format.Native)> _
Public Structure SimpleType
Implements INullable

Public Overrides Function ToString() As String
...
End Function

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

Public Shared ReadOnly Property Null() As SimpleType
...
End Property

Public Shared Function Parse(ByVal s As SqlString) As SimpleType
...
End Function

End Structure

در C#:

 
[Serializable]
[Microsoft.SqlServer.Server.SqlUserDefinedType(Format.Native)]
public struct SimpleUdt : INullable
{
public override string ToString() { ... }
public bool IsNull { ... }
public static SimpleUdt Null
{
get { ... }
}
public static SimpleUdt Parse(SqlString s) { ... }
}

می توان این را در T-SQL بارگذاری (load) و استفاده کرد:

CREATE TYPE simpleudt FROM [myassembly].[SimpleUdt]
CREATE TABLE t (mycolumn simpleudt)

کی یک UDT ایجاد کنیم؟

UDTها در SQL Server 2005، یک مکانیزم توسعه پذیر object-relational نیستند؛ بلکه راهی برای گسترش scalar type system در database هستند. scalar type system شامل typeهای ستونی (columnar) است که با SQL Server (int، nvarchar، uniqueidentifier، و غیره) منتقل و استفاده می شوند. با UDTها، می توان یک typeجدید تعریف کرد که میتوان به جای یک built-in scalar type استفاده کرد. اگر type، یک value اتمی است که برای مدل شدن به عنوان یک ستون مناسب است، یک UDT ایجاد کنید.

کاندیدهای خوب جهت پیاده سازی یک UDT، شامل تاریخ custom و typeهای time data در تقویم های مختلف و typeهای currency data است. یک UDT، یک کلاس واحد است که در معرض همه رفتارهای (behavior) دردسترس روی type است و داده های بنیادی ذخیره شده توسط type را خلاصه می کند: کل data access از programmatic interface در UDT استفاده می کنند. اغلب می توان از functionality موجود در .NET framework — از قبیل بین المللی کردن (internationalization) یا calendar functionality — استفاده کرد تا functionality را که به سختی فراهم می شود، فراهم کرد.

کی یک UDT ایجاد نکنیم؟

از یک UDT نباید برای مدل سازی اشیای business از قبیل کارمندان، قراردادها، یا مشتری ها استفاده کرد. SQL Server با یک UDT به عنوان یک واحد (unit) رفتار می کند که به آن opaque است. بعضی از مسائل با UDTهای پیچیده، شامل محدودیت 8 کیلو بایتی برای typeها، محدودیتهای indexing، و این واقعیت است که کل value باید هنگامی که هر value در UDT، update می شود، update شود.

فاکتورهایی که هنگام طراحی یک UDT باید در نظر گرفت

از آنجاییکه UDTها ستونی هستند، می توان index ها را، روی کل valueهای UDT تعریف کرد؛ همانطور که referential integrity constraint، از قبیل unique بودن، را می توان. همچنین می توان از UDTها در مقایسه و مرتب کردن سناریوها استفاده کرد.

مقایسه Valueهای UDT، بوسیله مقایسه binary representation of the type انجام می شود. اگر از Format.Native به عنوان مکانیزم پایداری (persistence mechanism) استفاده شود، آنگاه یک persisted form با استفاده از همان ترتیب field، به عنوان آنچه که در type تعریف می شود، ایجاد می شود؛ پس باید دقت کرد که آنها در جای صحیح قرار می گیرند.

غیر از مقایسه، هر عملیاتی روی یک UDT، نیازمند این است که UDT value، de-serialize شود و یک متد، فراخوانده شود. این الگو (pattern) موجب تحمیل بار اضافی روی server می شود، که باید هنگام تصمیم گیری در مورد اینکه آیا آن را به عنوان یک UDT، مدلسازی کنیم یا نکنیم، مد نظر قرار بگیرد. UDTها زمانی که یک type ،که نیاز به model شدن دارد، رفتارهای پیچیده ای دارد، مفیدتر هستند. اگرtype نسبتاً ساده باشد، آنگاه شاید بهتر باشد از ساختار UDT پرهیز کنیم.

نهایتاً، می توان از متدهای static یک UDT به عنوان یک مکانیزم بسته بندی (packaging) راحت جهت ذخیره سازی library تابعهای مربوط استفاده کرد. متدهای static را می توان از T-SQL با استفاده از syntaz زیر فراخوانی کرد:

select Type::Function(@arg1)

مثال: تاریخ های غیر غربی

می خواهیم valueهای زمان و تاریخ را با استفاده از تقویم "ام القرا" که با تقویم گریگوری که SQL Server datetime data type از آن استفاده می کند، ذخیره کنیم. می خواهیم این data type همان رفتارهای پایه ای را داشته باشد، بویژه string conversion، قابلیت بازیابی اجزای data، و محاسبات تاریخ و غیره.

مثال زیر از یک type تعریف شده توسط کاربر، یک پیاده سازی ساده از این data type است، و از UmAlQuraCalendar type استفاده می کند، که در نسخه 2.0 .NET Framework جدید است. متوجه شدن این مثال کمک زیادی به فراهم کردن متذهای لازم می کند.

UDT ام القرا در C#

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

[Serializable]
[SqlUserDefinedType(Format.Native, IsByteOrdered = true)]
public struct UmAlQuraDateTime : INullable
{

/*
* Private state.
*/

private long dtTicks;
private bool isNull;

// Calendar object used for all calendar-specific operations
private static readonly UmAlQuraCalendar s_calendar =
new UmAlQuraCalendar();

// For correct formatting we need to provie a culture code for
// a country that uses the Um Al Qura calendar: Saudi Arabia.
private static readonly CultureInfo ci =
new CultureInfo("ar-SA", false);


/*
* Null-Handling
*/

// get a null instance
public static UmAlQuraDateTime Null
{
get
{
UmAlQuraDateTime dt = new UmAlQuraDateTime();
dt.isNull = true;
return dt;
}
}

public bool IsNull
{
get
{
return this.isNull;
}
}

/*
* Constructors
*/

public UmAlQuraDateTime(long ticks)
{
isNull = false;
dtTicks = ticks;
}

public UmAlQuraDateTime(DateTime time) : this(time.Ticks)
{
}

/*
* Factory routines.
*/

public static UmAlQuraDateTime Parse(SqlString s)
{
if (s.IsNull) return Null;
DateTime t = DateTime.Parse(s.Value);
return new UmAlQuraDateTime(t);
}

public static UmAlQuraDateTime ParseArabic(SqlString s)
{
if (s.IsNull) return Null;
DateTime t = DateTime.Parse(s.Value, ci);
return new UmAlQuraDateTime(t);
}

public static UmAlQuraDateTime FromSqlDateTime(SqlDateTime d)
{
if (d.IsNull) return Null;
return new UmAlQuraDateTime(d.Value);
}

public static UmAlQuraDateTime Now
{
get
{
return new UmAlQuraDateTime(DateTime.Now);
}
}

/*
* Conversion Routines
*/

public DateTime DateTime
{
get { return new DateTime(this.dtTicks); }
}

public SqlDateTime ToSqlDateTime()
{
return new SqlDateTime(this.DateTime);
}

public override String ToString()
{
return this.DateTime.ToString(ci);
}

public String ToStringUsingFormat(String format)
{
return this.DateTime.ToString(format, ci);
}

/*
* Methods for getting date parts.
*/

public int Year
{
get
{
return s_calendar.GetYear(this.DateTime);
}
}

public int Month
{
get
{
return s_calendar.GetMonth(this.DateTime);
}
}

public int Day
{
get
{
return s_calendar.GetDayOfMonth(this.DateTime);
}
}

/*
* Date arithmetic methods.
*/

public UmAlQuraDateTime AddYears(int years)
{
return new
UmAlQuraDateTime(s_calendar.AddYears(this.DateTime, years));
}

public UmAlQuraDateTime AddDays(int days)
{
return new
UmAlQuraDateTime(s_calendar.AddDays(this.DateTime, days));
}

public double DiffDays(UmAlQuraDateTime other)
{
TimeSpan diff = DateTime.Subtract(other.DateTime);
return diff.Days;
}
}

وقتی این type در SQL Server بارگذاری می شود، می توان این type از طریق T-SQL استفاده کرد. در زیر چند مثال T-SQL آورده شده اند که از این UDT و خروجیی که بدست می آورند، استفاده می کنند.

ابتدا یک تاریخ ام القرا را parse و سپس آن را در دو فرمت با معادلهای غربی چاپ می کنیم:

 

DECLARE @d UmAlQuraDateTime
SET @d = UmAlQuraDateTime::ParseArabic('01/02/1400')
PRINT @d.ToString()
PRINT @d.ToStringUsingFormat('F')
PRINT @d.ToSqlDateTime()

نتیجه زیر حاصل می آید:

 

clip_image001


 

می توانیم تاریخ های غربی را نیز به ام القرا تبدیل کنیم:

DECLARE @n DateTime
SET @n = 'March 20, 2005'
DECLARE @d UmAlQuraDateTime
SET @d = UmAlQuraDateTime::FromSqlDateTime(@n)
PRINT @n
PRINT @d.ToString()

نتیجه:

clip_image001[8]

نهایتاً، بااین type می توانیم جداولی را با ستون، ایجاد و اصلاح کنیم:

 
CREATE TABLE dates (
western DateTime,
umalqura UmAlQuraDateTime
)

INSERT INTO dates(western) VALUES ('June 1, 2005')
INSERT INTO dates(western) VALUES ('July 1, 2005')

UPDATE dates
SET umalqura = UmAlQuraDateTime::FromSqlDateTime(dates.western)

SELECT western, umalqura.ToString() as umalqura FROM dates

این جدول، نتیجه نهایی است:

 
 
clip_image001[10]
 
 
 

نتیجه گیری

این مقاله، راهنماییها، سناریوهای استفاده واقعی، و نمونه هایی را با استفاده از ویژگیهای CLR integration در SQL Server 2005، ارائه کرده است. برنامه نویسان و معماران (Database application developers and architects) باید از این مقاله جهت ترکیب با documentation در ویژگیهای دیگر SQL Server 2005، از قبیل Transact-SQL، XML، و Service Broker استفاده کنند.


برای دانلود کتابها و مقالات بیشتر به سایت http://www.tahlildadeh.com مراجعه نمایید.