微软向来为开发软件提供了友善的开发环境,若你不想徒手创建程序代码,可以直接使用 Visual Studio 2005 的SQL Server 项目类型中的模板(Template)来开发。在项目名称上点选右键新建项目,打开如图11-21 的窗口,选择 User-Defined Type,点选“添加”按钮后 Visual Studio 2005 将会帮你创建如程序代码列表 11-10 的模板,而你只需要在模板中的各函数内填入商业逻辑即可。
图11-21 在 Visual Studio 2005 项目中新建UDT的模板
模板内容如下:
程序代码列表11-10 Visual Studio 2005 为用户自定义数据类型提供的开发模板
Imports System
Imports System.Data
Imports System.Data.SqlClient
Imports System.Data.SqlTypes
Imports Microsoft.SqlServer.Server
<Serializable()> _
<Microsoft.SqlServer.Server.SqlUserDefinedType(Format.Native)> _
Public Structure UserDefineType
Implements INullable
Public Overrides Function ToString() As String
' Put your code here
Return ""
End Function
Public ReadOnly Property IsNull() As Boolean Implements INullable.IsNull
Get
' Put your code here
Return m_Null
End Get
End Property
Public Shared ReadOnly Property Null As UserDefineType
Get
Dim h As UserDefineType = New UserDefineType
h.m_Null = True
Return h
End Get
End Property
Public Shared Function Parse(ByVal s As SqlString) As UserDefineType
If s.IsNull Then
Return Null
End If
Dim u As UserDefineType = New UserDefineType
' Put your code here
Return u
End Function
' This is a place-holder method
Public Function Method1() As String
' Put your code here
Return "Hello"
End Function
' This is a place-holder static method
Public Shared Function Method2() As SqlString
' Put your code here
Return New SqlString("Hello")
End Function
' This is a place-holder field member
Public m_var1 As Integer
' Private member
Private m_Null As Boolean
End Structure
由上面的模板程序架构我们可以发现实现 UDT 的时候,SQL Server 2005 规定必须先完成下列步骤:
1. 创建 Public 类(Class)或结构(Structure)。
2. 在类中定义 Serializable 与 SqlUserDefinedTypeAttribute 特性(Attribute)。
3. 处理数据字段的NULL值
为了处理数据字段的 NULL 值,因此UDT 必须要实现 INullable 接口,若某条记录的字段值需要是 NULL,例如添加记录,而该自定义数据类型字段存放的是 NULL 时,才有得对应。该界面只有一个返回布尔类型的 IsNull 属性,以此告知该实例所代表的内容是否为 NULL。
除了实现 INullable 接口外,还必须编写一个 Public 属性名称为 NULL、返回内容为 NULL 的实例。实现这个属性对用户自定义数据类型来说是必要的,让前端程序在访问字段内容为 NULL 的记录时,SQL Server 能够通过它取得意义为 NULL 的对象实例。若你没有实际操作它,在编译与注册组件时不会出错(这时还不知道这个程序集要做什么J),但在注册用户自定义数据类型时会出错。
4. 提供 String 的转换:实现静态 Parse 方法与覆写(Overrides)继承自 Object 的 ToString 方法,也就是提供字符串与 UDT 类型的转换。Parse 提供从字符串转换为对象,而 ToString 提供从对象转换为字符串的方式。
5. 提供 Public 属性去访问类中所定义的 Private数据。
上述第二点中,SqlUserDefinedTypeAttribute 属性的 Format 枚举参数告知要如何将对象实例序列化后放置到数据表的字段内,它的枚举类型有三:
l Format.Native:序列化对象实例时最为有效率,但缺乏弹性。只可以用在该类型所有需要存储(persist)属性的数据类型都是固定长度,例如数值、日期等数据类型,也就是单纯值类型(value-type)的变量才可以使用,而对象或字符串类型就不可以,因为它是参照类型的变量。
l Format.UserDefined:此定义兼具弹性与效率,但用户需要自定义序列化的方式,也就是类型或结构需要实现 IBinarySerialize接口,该界面有Write 和 Read 两个方法。而这个属性还需要搭配 MaxByteSize 属性的设置。
l Unknown:序列化的格式未知。
SqlUserDefinedTypeAttribute 属性上还有一些其他选择性参数设置,分别描述如下:
l IsByteOrdered:存放序列化后的对象个体的字节是否可作为排序顺序。Format 参数需要设置成 Native 或 UserDefined,IsByteOrdered 才可以设为 True。设为 True 后,该数据类型以序列化后的字节来对比大小,也就依此排序与创建索引,默认值为 False。
l IsFixedLength:自定义数据类型的各实例序列化后,存放在数据表字段内是否为固定长度,默认为 false。
l MaxByteSize:自定义数据类型的实例最大的字节数,当 Format 参数设置为 Native 时,不可以设置这个参数,但若 Format 设置的是 UserDefined,则一定要设置这个参数。
接下来,我们用两个 VB.NET 所实现的 UDT 类当作范例来解释,Seat 类使用的 Format 参数为 Native ,而 Desk 类使用的 Format 参数是 UserDefined,后续将提供一些高级的讨论。
11.3.4.2 用户自定义数据类型的基本范例
首先是简单地赋予模板程序逻辑内容的 Seat 类,其声明与 INullable “接口”的实现如程序代码列表11-11:
程序代码列表 11-11 声明用户自定义类型的类,并实际操作 INullable 接口
'User Defined Type 一定需要能够 Searialize 才能整个地放到数据表字段中
'若不指定名字,会自动以 Class 名当做 Type 名称
<Serializable(), SqlUserDefinedType(Format.Native), _
Runtime.InteropServices.StructLayout(LayoutKind.Sequential)> _
Public Class Seat
Implements INullable
Private is_Null As Boolean = True
'由于序列化设置的是 Native,所以只能以 SQL 默认的数据类型组合
Private m_size As Short
Private m_type As Short
Public Sub New()
'初始化创建自定义数据类型的对象实例时,设置
'代表 Null 的各属性意义,避免用户直接访问内
'涵为 Null 的实例之属性
m_size = -1
m_type = -1
is_Null = True
End Sub
'实现 INullable “接口”唯一的 IsNull 属性
Public ReadOnly Property IsNull() As Boolean _
Implements System.Data.SqlTypes.INullable.IsNull
Get
Return is_Null
End Get
End Property
由于在程序代码列表11-11的范例中定义序列化的方式为 Format.Native,因此需要存储的 Private 类型变量 is_NULL、m_size、m_type 我们都定义成固定长度的数据类型,如 Boolean 或 Short。变量不可以声明成String 类型,因为它是不固定长度。
而通过 IsNull 属性返回 SQL Server 告知该实例是否为 NULL ,程序逻辑很简单,就是返回 is_NULL 类型变量当时的设置值。
接下来是设置 Seat 类中返回给数据字段或变量是 NULL 值的静态 Public 属性,实现的方式也很简单,内容如程序代码列表11-12:
程序代码列表11-12 实际操作NULL属性,返回我们所设置的内容代表NULL的对象实例
'通过 NULL 返回包含值定义为 NULL 的对象个体
Public Shared ReadOnly Property NULL() As Seat
Get
Dim sea As New Seat
sea.is_NULL = True
Return (sea)
End Get
End Property
在 NULL 属性中,我们返回一个新的 Seat 实例,并设置该实例代表 NULL 的方式,当 SQL Server 需要返回存入数据表的记录,在用户自定义数据类型的字段值是 NULL 时,便通过这个属性函数创建实例。
除了可以存储与显示 NULL 外,UDT 也必须提供实例与字符串间转换的能力。因此必须实现静态Parse 方法,在传入单一 SqlString 类型代表对象实例的文本参数后,与 NULL 属性一样返回对象的实例,但该对象实例的内涵与该字符串的意义相同。也就是提供字符串与 UDT 类型的转换。程序代码范例如程序代码列表11-13:
程序代码列表11-13 实际操作 Parse 函数,将字符串转成自定义数据类型的实例
Public Shared Function Parse(ByVal s As SqlString) As Seat
'传进来的数据应该是 N'10,赛车椅' 的格式,与 ToString 呼应
Dim sea As New Seat
If s.IsNull Then
Return Nothing
Else
Try
Dim strAry() As String = s.ToString.Split(",")
sea.Size = Short.Parse(strAry(0))
sea.Type = strAry(1)
Catch
'若用户输入的数据类型不对,或是无法设置到相关的属性
'默认给定的值
sea.Size = -1
sea.Type = "类型不明"
End Try
End If
Return sea
End Function
因为在 Seat 类中,我们定义了两个属性:Size 和 Type,因此在程序代码列表 11-13 中,要求输入的字符串一定要通过逗号分隔两种属性的值,在建立了对象实例后,分别赋予各属性再返回该实例。
反过来,当用户要将实例转成文本类型时,我们要通过覆写(Override) .NET Framework 规范的 Object 对象之 ToString 方法,让 UDT 提供从实例转换成字符串的方式。程序代码范例如列表11-14:
程序代码列表11-14 覆写Object的ToString 函数,将自定义数据类型的实例转成字符串
'需要提供 ToString,Parse 以及 Null 让 UDT 正常运行
'通过覆写 ToString,让显示数据时可以通过 T-SQL Convert 该 Type
'成字符串类型
Public Overrides Function ToString() As String
If Me.IsNull Then
Return "NULL"
Else
Return Me.Size.ToString() & "," & Me.Type
End If
End Function
范例中,我们仅是简单地将两项属性组成字符串后返回,并呼应程序代码列表 11-13 所实现的 Parse 函数,两项属性间以逗号隔开。
上述的程序对象在部署之后可以通过以下的 T-SQL 语法测试字符串与对象实例的转换:
SELECT CONVERT(Seat,N'0,赛车椅').Type
我们将 “0,赛车椅” 字符串通过 CONVERT 函数转型成 Seat 对象类实例,SQL Server 就是调用我们先前实现的 Parse 属性。并通过该类的实例取回自定义数据类型的 Type 属性,所得到的结果如图11-22 所示:
图11-22 测试Convert 的功能所得到的结果
另外,类中用来访问与设置Type 和Size属性的Get 和Set 函数定义如程序代码列表11-15:
程序代码列表11-15 自定义的Seat数据类型提供Size和Type两个属性
Public Property Size() As Short
Get
Return Me.m_size
End Get
Set(ByVal Value As Short)
m_size = Value
Me.is_Null = False
End Set
End Property
Public Property Type() As String
'强制用户输入的 Type 只能是赛车椅,飞行椅或香蕉椅
Get
Select Case Me.m_type
Case -1
Return "类型不明"
Case 0
Return "赛车椅"
Case 1
Return "飞行椅"
Case 2
Return "香蕉椅"
Case Else
Return "类型不明"
End Select
End Get
Set(ByVal Value As String)
Select Case Value
Case "类型不明"
m_type = -1
Case "赛车椅"
m_type = 0
Case "飞行椅"
m_type = 1
Case "香蕉椅"
m_type = 2
Case Else
Throw New ArgumentException( _
"Type 类型必须填入赛车椅,飞行椅,香蕉椅三者之一")
End Select
If m_type >= 0 Then Me.is_Null = False
End Set
End Property
上一页 [1] [2] [3] [4] [5] [6] 下一页
责任编辑:cyth