SQL2005 用户自定义类型
????? 之前對這個“用戶自定義類型”只是有所耳聞,沒有機會用過,也沒有自己動手去寫過。今天朋友讓我寫一個簡單的“用戶自定義類型”,呵呵,糗了。
????? 下面是目前對它的了解。
在VS2008中新建項目選擇“數據庫”—“SQL Server項目”,上面的combobox選擇".NET Framework2.0"
?
輸入項目名稱,選擇好自己的項目所在文件夾,點解確認后,會提示:
選擇要使用“用戶自定義類型”的數據庫,在“添加新引用”中找到目標數據庫,點擊“確定”即可。
進入項目后,在解決方案上“右鍵”—“添加”—“用戶定義的類型”。如圖所示
在這里面可以添加“用戶定義的函數”、“存儲過程”、“聚合”、“觸發器”等。選擇“用戶定義的類型”,后便可看到可以編輯的代碼層。
下面,在進行編碼前,我們來了解一些內容,呵呵,這些內容,也是我邊做邊查的。呵呵,很慶幸,碰到不會的東西,能查一查,問一問,呵呵,也是件很好的事情。
1.實現“用戶定義的類型”UDT的要求:
UDT 必須通過創建公共的 static(Microsoft Visual Basic 中為 Shared)Null 方法,在類或結構中實現 System.Data.SqlTypes.INullable 接口。默認情況下,SQL Server 是可識別 Null 的。這是為使在 UDT 中執行的代碼能夠識別 Null 值所必需的。這個對應的就是上面的代碼 public struct TypeTest:INullable。需要實現Null性,對null性的處理,是在這里處理的。
?
1???public?static?TypeTest?Null2?????{
3?????????get
4?????????{
5?????????????TypeTest?h?=?new?TypeTest();
6?????????????h.m_Null?=?true;
7?????????????return?h;
8?????????}
9?????}
必須創建一個名為 IsNull 的屬性,在從 CLR 代碼中確定值是否為空值時,需要使用該屬性。SQL Server 發現 UDT 的空值實例時,將使用正常的空值處理方法保持該實例。服務器不會將時間浪費在序列化或反序列化 UDT 上(如果不是必須),也不會將空間浪費在存儲空值 UDT 上。這種空值檢查在每次從 CLR 引入 UDT 時執行,這意味著始終可以使用 Transact-SQL IS NULL 結構檢查空值 UDT。服務器也使用 IsNull 屬性來測試實例是否為空值。服務器確定 UDT 為空值后,可以使用其本機空值處理方法。
?
UDT 必須包含支持從其進行分析的公共 static (或 Shared)Parse 方法以及用于轉換到對象的字符串表示形式的 ToString 方法。該方法的處理,是在這段代碼中進行處理的:
1???public?override?string?ToString()2?????{
3?????????//?用您的代碼替換下列代碼
4?????????return?"";
5?????}
?
具有用戶定義序列化格式的 UDT 必須實現 System.Data.IBinarySerialize 接口并提供 Read 和 Write 方法。
對Read和Write方法的實現是在實現接口IBinarySerialize時需要處理的。處理方法如下:
?
代碼 ?1??2?????public?string?result;
?3?
?4?????public?void?Read(System.IO.BinaryReader?r)?
?5?????{
?6?
?7?????????this.result?=?r.ReadString();
?8?????}
?9?
10?????public?void?Write(System.IO.BinaryWriter?w)?
11?????{
12?
13?????????w.Write(this.result);
14?????}
?
這段代碼需要自己手動的寫上去,實現Read和Write方法。
下面是編寫用戶自定義類型的其他要求:
該 UDT 必須實現 System.Xml.Serialization.IXmlSerializable,或者所有公共字段和屬性必須均屬于 XML 可序列化類型或者使用 XmlIgnore 屬性進行修飾(如果要求替代標準序列化)。一個 UDT 對象必須只存在一個序列化。如果序列化或反序列化例程識別了某一特定對象的多個表示形式,則驗證將失敗。
為了確保服務器將字節順序的比較用于 UDT 值,SqlUserDefinedTypeAttribute.IsByteOrdered 必須為 true。
在類中定義的 UDT 必須具有不采用任何參數的公共構造函數。您可以選擇創建其他重載類構造函數。
該 UDT 必須將數據元素作為公共字段或屬性過程公開。
公共名稱不能長于 128 個字符,并且必須符合在標識符中定義的針對標識符的 SQL Server 命名規則。
sql_variant 列不能包含 UDT 的實例。
繼承的成員無法從 Transact-SQL 訪問,因為 SQL Server 類型系統不知道 UDT 中的繼承層次結構。但是,您可以在創建類的結構時使用繼承,并且可以在該類型的托管代碼實現方式中調用此類方法。
成員不能被重載,但類構造函數除外。如果您創建某一重載方法,則在 SQL Server 中注冊程序集或創建類型時將不會引發錯誤。在運行時將檢測到重載的方法,而不是在創建類型時檢測到。只要永不調用重載的方法,重載的方法就可以存在于類中。一旦您調用重載的方法,就會引發錯誤。
任何 static(或 Shared)成員都必須聲明為常量或聲明為只讀。靜態成員將無法改變。
從 SQL Server 2008 開始,如果 SqlUserDefinedTypeAttribute.MaxByteSize 字段設置為 -1,則序列化 UDT 在大小上可達到大對象 (LOB) 大小限制(目前為 2 GB)。該 UDT 的大小不能超過在 MaxByteSized 字段中指定的值。
編寫用戶類型的本地序列化:
為 UDT 選擇正確的序列化屬性取決于您正嘗試創建的 UDT 的類型。 Native 序列化格式利用了一個非常簡單的結構,使 SQL Server 能夠在磁盤上存儲 UDT 的有效本機表示形式。如果 UDT 為簡單形式并且只包含以下類型的字段,則建議采用 Native 格式:
bool、byte、sbyte、short、ushort、int、uint、long、ulong、float、double、SqlByte、SqlInt16、SqlInt32、SqlInt64、SqlDateTime、SqlSingle、SqlDouble、SqlMoney, SqlBoolean
由上述類型的字段構成的值類型十分適合于 Native 格式,例如 C# 中的 structs(或者 Visual Basic 中已知的 Structures)。例如,用 Native 序列化格式指定的 UDT 可以包含也用 Native 格式指定的其他 UDT 的字段。如果 UDT 定義更復雜并且所包含的數據類型不在上述列表中,您必須改為指定 UserDefined 序列化格式。
Native 格式具有以下要求:
-
該類型不得指定 MaxByteSize 的值。
-
所有字段必須都是可序列化的。
-
如果 UDT 是在類中定義的并且不是結構,則必須將 StructLayoutAttribute 指定為 StructLayout.LayoutKindSequential。此屬性控制數據字段的實際布局并用于強制成員按它們出現的順序排列。SQL Server 使用此屬性確定具有多個值的 UDT 的字段順序。
用戶自定義序列化,在我們自己編寫“用戶自定義類型”時,需要使用UserDefined,即需要將系統自動生成的代碼
[Microsoft.SqlServer.Server.SqlUserDefinedType(Format.Native)]修改為:
[Microsoft.SqlServer.Server.SqlUserDefinedType(Format.UserDefined)]
SqlUserDefinedTypeAttribute 屬性的 UserDefined 格式設置使開發人員能夠完全控制二進制格式。在將 Format 特性屬性指定為 UserDefined 時,您需要在代碼中采取以下操作:
-
指定可選的 IsByteOrdered 特性屬性。默認值為 false。
-
指定 SqlUserDefinedTypeAttribute 的 MaxByteSize 屬性。
-
通過實現 IBinarySerialize 接口,編寫代碼以便為 UDT 實現 Read 和 Write 方法。
好了,上面的內容是我們再進行編寫我們自己的“用戶自定義類型”前需要了解的,呵呵。我也是了解了這么多,然后就開始試著寫自己的“用戶自定義類型”。例子比較簡單,就是把輸入的時間統一成一個時間格式。希望能達到理解“用戶自定義類型”的目的。代碼如下:
?
代碼 ?1?using?System;?2?using?System.Data;
?3?using?System.Data.SqlClient;
?4?using?System.Data.SqlTypes;
?5?using?Microsoft.SqlServer.Server;
?6?
?7?[Serializable]
?8?[Microsoft.SqlServer.Server.SqlUserDefinedType(Format.UserDefined,MaxByteSize=4000)]
?9?public?struct?TypeTime?:?INullable,IBinarySerialize
10?{
11?????#region//實現IBinarySerizlize的Read和Write方法
12?
13?????public?string?result;
14?
15?????public?void?Read(System.IO.BinaryReader?r)?
16?????{
17?
18?????????this.result?=?r.ReadString();
19?????}
20?
21?????public?void?Write(System.IO.BinaryWriter?w)?
22?????{
23?
24?????????w.Write(this.result);
25?????}
26?
27?????#endregion
28?
29?????public?override?string?ToString()
30?????{
31?????????//?用您的代碼替換下列代碼
32?????????return?result;
33?????}
34?
35?????public?bool?IsNull
36?????{
37?????????get
38?????????{
39?????????????//?在此處放置代碼
40?????????????return?m_Null;
41?????????}
42?????}
43?
44?????public?static?TypeTime?Null
45?????{
46?????????get
47?????????{
48?????????????TypeTime?h?=?new?TypeTime();
49?????????????h.m_Null?=?true;
50?????????????return?h;
51?????????}
52?????}
53?
54?????public?static?TypeTime?Parse(SqlString?s)
55?????{
56?????????if?(s.IsNull)
57?????????????return?Null;
58?????????TypeTime?u?=?new?TypeTime();
59?????????//?在此處放置代碼
60?????????u.result?=?OneTime(s);
61?????????return?u;
62?????}
63?
64?????///?<summary>
65?????///?將輸入的時間格式統一
66?????///?</summary>
67?????///?<param?name="str"></param>
68?????///?<returns></returns>
69?????public?static?string?OneTime(SqlString?str)
70?????{
71?????????return?Convert.ToDateTime(str.Value).ToShortDateString()?+?Convert.ToDateTime(str.Value).ToShortTimeString();
72?????}
73????
74?
75?????//?私有成員
76?????private?bool?m_Null;
77?}
78?
79?
80?
?
其中系統自動生成的兩個方法
代碼 ?1???//?這是占位符方法?2?????public?string?Method1()
?3?????{
?4?????????//在此處插入方法代碼
?5?????????return?"Hello";
?6?????}
?7?
?8?????//?這是占位符靜態方法
?9?????public?static?SqlString?Method2()
10?????{
11?????????//在此處插入方法代碼
12?????????return?new?SqlString("Hello");
13?????}
Method1和Method2可以刪掉,替換成自己的方法。
其中需要注意的問題有這么幾個:
1.[Microsoft.SqlServer.Server.SqlUserDefinedType(Format.UserDefined,MaxByteSize=4000)]
public struct TypeTest : INullable,IBinarySerialize? 需要同時實現INullable和IBinarySeralize兩個接口;
2.實現IBinarySeralize的Read和Write兩個方法;
3.SqlString是數據庫類型,使用的時候,需要使用它的.value屬性,轉換成數據類型string 才能使用。
好了,這個問題被解決掉了。
碰到問題的時候,要冷靜,知道自己想要什么,剩下的就是想辦法去拿;自己不知道怎么能拿到,呵呵,就看看誰拿到了,然后跟人家學就好了。話是這么說的,我也是這么告訴自己的,呵呵,有時候,我也會因為某個問題沒能解決頭大。慢慢來,告訴自己冷靜就好,問題的產生,就是用來解決的。開心,好運!
?
?
?
轉載于:https://www.cnblogs.com/angleSJW/archive/2010/04/20/1716282.html
總結
以上是生活随笔為你收集整理的SQL2005 用户自定义类型的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: SEO优化之一步一步诊断网站
- 下一篇: 【转贴】大型ORACLE数据库优化设计方