天天看點

SQL Server CLR全功略之五---CLR自定義資料類型

一、這是這個系列的最後一節了,自定義複雜資料類型目前隻能通過CLR來實作。為了在 SQL Server 中運作,您的 UDT 必須實作 UDT 定義中的以下要求:

1.該 UDT 必須指定 Microsoft.SqlServer.Server.SqlUserDefinedTypeAttribute。System.SerializableAttribute 可選用,但建議使用。

2.UDT 必須通過建立公共的 static(Microsoft Visual Basic 中為 Shared)Null 方法,在類或結構中實作 System.Data.SqlTypes.INullable 接口。預設情況下,SQL Server 是可識别 Null 的。這是為使在 UDT 中執行的代碼能夠識别 Null 值所必需的。

3.UDT 必須包含支援從其進行分析的公共 static (或 Shared)Parse 方法以及用于轉換到對象的字元串表示形式的 ToString 方法。

4.具有使用者定義序列化格式的 UDT 必須實作 System.Data.IBinarySerialize 接口并提供 Read 和 Write 方法。

5.該 UDT 必須實作 System.Xml.Serialization.IXmlSerializable,或者所有公共字段和屬性必須均屬于 XML 可序列化類型或者使用 XmlIgnore 屬性進行修飾(如果要求替代标準序列化)。

6.一個 UDT 對象必須隻存在一個序列化。如果序列化或反序列化例程識别了某一特定對象的多個表示形式,則驗證将失敗。

7.為了確定伺服器将位元組順序的比較用于 UDT 值,SqlUserDefinedTypeAttribute.IsByteOrdered 必須為 true。

8.在類中定義的 UDT 必須具有不采用任何參數的公共構造函數。您可以選擇建立其他重載類構造函數。

9.該 UDT 必須将資料元素作為公共字段或屬性過程公開。

10.公共名稱不能長于 128 個字元,并且必須符合在辨別符中定義的針對辨別符的 SQL Server 命名規則。

11.sql_variant 列不能包含 UDT 的執行個體。

12.繼承的成員無法從 Transact-SQL 通路,因為 SQL Server 類型系統不知道 UDT 中的繼承層次結構。但是,您可以在建立類的結構時使用繼承,并且可以在該類型的托管代碼實作方式中調用此類方法。

13.成員不能被重載,但類構造函數除外。如果您建立某一重載方法,則在 SQL Server 中注冊程式集或建立類型時将不會引發錯誤。在運作時将檢測到重載的方法,而不是在建立類型時檢測到。隻要永不調用重載的方法,重載的方法就可以存在于類中。一旦您調用重載的方法,就會引發錯誤。

14.任何 static(或 Shared)成員都必須聲明為常量或聲明為隻讀。靜态成員将無法改變。

15.從 SQL Server 2008 開始,如果 SqlUserDefinedTypeAttribute.MaxByteSize 字段設定為 -1,則序列化 UDT 在大小上可達到大對象 (LOB) 大小限制(目前為 2 GB)。該 UDT 的大小不能超過在 MaxByteSized 字段中指定的值。

二、下面的代碼實作了坐标的自定義類型

[c-sharp]  view plain copy

  1. using System;  
  2. using System.Collections.Generic;  
  3. using System.Text;  
  4. using Microsoft.SqlServer.Server;  
  5. using System.Runtime.InteropServices;  
  6. using System.Data.SqlTypes;  
  7. [Serializable]  
  8. [StructLayout(LayoutKind.Sequential)]  
  9. [SqlUserDefinedType(Format.Native, IsByteOrdered = true)]  
  10. public class UDT_Point : INullable  
  11. {  
  12.     private int x;  
  13.     /// <summary>  
  14.     /// X坐标  
  15.     /// </summary>  
  16.     public int X  
  17.     {  
  18.         get { return x; }  
  19.         set { x = value; }  
  20.     }  
  21.     private int y;  
  22.     /// <summary>  
  23.     /// Y坐标  
  24.     /// </summary>  
  25.     public int Y  
  26.     {  
  27.         get { return y; }  
  28.         set { y = value; }  
  29.     }  
  30.     //是否為NULL标志  
  31.     private bool _isNull;  
  32.     public UDT_Point(int x, int y)  
  33.     {  
  34.         this._isNull = false;  
  35.         this.x = x;  
  36.         this.y = y;  
  37.     }  
  38.     public UDT_Point()  
  39.     {  
  40.         this._isNull = true;  
  41.         this.x = this.y = 0;  
  42.     }  
  43.     /// <summary>  
  44.     /// 加法運算符  
  45.     /// </summary>  
  46.     /// <param name="item"></param>  
  47.     /// <returns></returns>  
  48.     [SqlMethod(OnNullCall = false)]  
  49.     public UDT_Point Add(UDT_Point item)  
  50.     {  
  51.         //被加數為空,直接傳回this  
  52.         if (item._isNull)  
  53.             return this;  
  54.         return new UDT_Point(item.x + this.x, item.y + this.y);  
  55.     }  
  56.     /// <summary>  
  57.     /// 減法運算符  
  58.     /// </summary>  
  59.     /// <param name="item"></param>  
  60.     /// <returns></returns>  
  61.     [SqlMethod(OnNullCall = false)]  
  62.     public UDT_Point Minus(UDT_Point item)  
  63.     {  
  64.         //被減數為空,直接傳回this  
  65.         if (item._isNull)  
  66.             return this;  
  67.         return new UDT_Point(this.x - item.x, this.y - item.y);  
  68.     }  
  69.     /// <summary>  
  70.     /// 解析函數。必須有  
  71.     /// </summary>  
  72.     /// <param name="strString"></param>  
  73.     /// <returns></returns>  
  74.     public static UDT_Point Parse(SqlString strString)  
  75.     {  
  76.         int x = int.Parse(strString.Value.Split(',')[0]);  
  77.         int y = int.Parse(strString.Value.Split(',')[1]);  
  78.         return new UDT_Point(x, y);  
  79.     }  
  80.     /// <summary>  
  81.     /// 為空處理,必須有  
  82.     /// </summary>  
  83.     public static UDT_Point Null  
  84.     {  
  85.         get  
  86.         {  
  87.             return new UDT_Point();  
  88.         }  
  89.     }  
  90.     /// <summary>  
  91.     /// 顯示函數,必須有  
  92.     /// </summary>  
  93.     /// <returns></returns>  
  94.     public override string ToString()  
  95.     {  
  96.         return string.Format("({0},{1})", this.x, this.y);  
  97.     }  
  98.     #region INullable Members  
  99.     /// <summary>  
  100.     /// 實作為NULL接口  
  101.     /// </summary>  
  102.     public bool IsNull  
  103.     {  
  104.         get { return this._isNull; }  
  105.         set { this._isNull = true; }  
  106.     }  
  107.     #endregion  
  108. }  

三、部署及調用SQL腳本

CREATE TYPE dbo.UDT_Point

EXTERNAL NAME CLRDemoAssemly.[UDT_Point];

CLR系列文章連結:

SQL Server CLR全功略之一---CLR介紹和配置:

http://blog.csdn.net/tjvictor/archive/2009/10/25/4726933.aspx

SQL Server CLR全功略之二---CLR存儲過程:

http://blog.csdn.net/tjvictor/archive/2009/10/26/4731052.aspx

SQL Server CLR全功略之三---CLR标量函數、表值函數和聚合函數(UDA):

http://blog.csdn.net/tjvictor/archive/2009/11/10/4793781.aspx

SQL Server CLR全功略之四---CLR觸發器:

http://blog.csdn.net/tjvictor/archive/2009/11/10/4795569.aspx

SQL Server CLR全功略之五---CLR自定義資料類型

http://blog.csdn.net/tjvictor/archive/2009/11/13/4807901.aspx

如需轉載,請注明本文原創自CSDN TJVictor專欄:http://blog.csdn.net/tjvictor