一、这是这个系列的{zh1}一节了,自定义复杂数据类型目前只能通过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 中注册程序集或创建类型时将不会引发错误。在运行时将检测到重载的方法,而不是在创建类型时检测到。只要xx调用重载的方法,重载的方法就可以存在于类中。一旦您调用重载的方法,就会引发错误。
?
14.任何 static(或 Shared)成员都必须声明为常量或声明为只读。静态成员将无法改变。
?
15.从 SQL Server 2008 开始,如果 SqlUserDefinedTypeAttribute.MaxByteSize 字段设置为 -1,则序列化 UDT 在大小上可达到大对象 (LOB) 大小限制(目前为 2 GB)。该 UDT 的大小不能超过在 MaxByteSized 字段中指定的值。
?
?
?
二、下面的代码实现了坐标的自定义类型
?
view plaincopy to clipboardprint?
using System;??
using System.Collections.Generic;??
using System.Text;??
using Microsoft.SqlServer.Server;??
using System.Runtime.InteropServices;??
using System.Data.SqlTypes;??
?
[Serializable]??
[StructLayout(LayoutKind.Sequential)]??
[SqlUserDefinedType(Format.Native, IsByteOrdered = true)]??
public class UDT_Point : INullable??
{??
??? private int x;??
??? /// <summary>??
??? /// X坐标??
??? /// </summary>??
??? public int X??
??? {??
??????? get { return x; }??
??????? set { x = value; }??
??? }??
?
??? private int y;??
??? /// <summary>??
??? /// Y坐标??
??? /// </summary>??
??? public int Y??
??? {??
??????? get { return y; }??
??????? set { y = value; }??
??? }??
?
??? //是否为NULL标志??
??? private bool _isNull;??
??? public UDT_Point(int x, int y)??
??? {??
??????? this._isNull = true;??
??????? this.x = x;??
??????? this.y = y;??
??? }??
??? public UDT_Point()??
??? {??
??????? this._isNull = true;??
??????? this.x = this.y = 0;??
??? }??
??? /// <summary>??
??? /// 加法运算符??
??? /// </summary>??
??? /// <param name=”item”></param>??
??? /// <returns></returns>??
??? [SqlMethod(OnNullCall = false)]??
??? public UDT_Point Add(UDT_Point item)??
??? {??
??????? //被加数为空,直接返回this??
??????? if (item._isNull)??
??????????? return this;??
??????? return new UDT_Point(item.x + this.x, item.y + this.y);??
??? }??
??? /// <summary>??
??? /// 减法运算符??
??? /// </summary>??
??? /// <param name=”item”></param>??
??? /// <returns></returns>??
??? [SqlMethod(OnNullCall = false)]??
??? public UDT_Point Minus(UDT_Point item)??
??? {??
??????? //被减数为空,直接返回this??
??????? if (item._isNull)??
??????????? return this;??
??????? return new UDT_Point(this.x - item.x, this.y - item.y);??
??? }??
?
??? /// <summary>??
??? /// 解析函数。必须有??
??? /// </summary>??
??? /// <param name=”strString”></param>??
??? /// <returns></returns>??
??? public static UDT_Point Parse(SqlString strString)??
??? {??
??????? int x = int.Parse(strString.Value.Split(’,')[0]);??
??????? int y = int.Parse(strString.Value.Split(’,')[1]);??
??????? return new UDT_Point(x, y);??
??? }??
?
??? /// <summary>??
??? /// 为空处理,必须有??
??? /// </summary>??
??? public static UDT_Point Null??
??? {??
??????? get?
??????? {??
??????????? return new UDT_Point();??
??????? }??
??? }??
?
??? /// <summary>??
??? /// 显示函数,必须有??
??? /// </summary>??
??? /// <returns></returns>??
??? public override string ToString()??
??? {??
??????? return string.Format(”({0},{1})”, this.x, this.y);??
??? }?
?
??? #region INullable Members??
??? /// <summary>??
??? /// 实现为NULL接口??
??? /// </summary>??
??? public bool IsNull??
??? {??
??????? get { return this._isNull; }??
??????? set { this._isNull = true; }??
??? }?
??? #endregion??
}?
using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.SqlServer.Server;
using System.Runtime.InteropServices;
using System.Data.SqlTypes;
?
[Serializable]
[StructLayout(LayoutKind.Sequential)]
[SqlUserDefinedType(Format.Native, IsByteOrdered = true)]
public class UDT_Point : INullable
{
??? private int x;
??? /// <summary>
??? /// X坐标
??? /// </summary>
??? public int X
??? {
???? ???get { return x; }
??????? set { x = value; }
??? }
?
??? private int y;
??? /// <summary>
??? /// Y坐标
??? /// </summary>
??? public int Y
??? {
??????? get { return y; }
??????? set { y = value; }
??? }
?
??? //是否为NULL标志
??? private bool _isNull;
??? public UDT_Point(int x, int y)
??? {
??????? this._isNull = true;
??????? this.x = x;
??????? this.y = y;
??? }
??? public UDT_Point()
??? {
??????? this._isNull = true;
??????? this.x = this.y = 0;
??? }
??? /// <summary>
??? /// 加法运算符
??? /// </summary>
??? /// <param name=”item”></param>
??? /// <returns></returns>
??? [SqlMethod(OnNullCall = false)]
??? public UDT_Point Add(UDT_Point item)
??? {
??????? //被加数为空,直接返回this
??????? if (item._isNull)
??????????? return this;
??????? return new UDT_Point(item.x + this.x, item.y + this.y);
??? }
??? /// <summary>
??? /// 减法运算符
??? /// </summary>
??? /// <param name=”item”></param>
??? /// <returns></returns>
??? [SqlMethod(OnNullCall = false)]
??? public UDT_Point Minus(UDT_Point item)
??? {
??????? //被减数为空,直接返回this
??????? if (item._isNull)
??????????? return this;
??????? return new UDT_Point(this.x - item.x, this.y - item.y);
??? }
?
??? /// <summary>
??? /// 解析函数。必须有
??? /// </summary>
??? /// <param name=”strString”></param>
??? /// <returns></returns>
??? public static UDT_Point Parse(SqlString strString)
??? {
??????? int x = int.Parse(strString.Value.Split(’,')[0]);
??????? int y = int.Parse(strString.Value.Split(’,')[1]);
??????? return new UDT_Point(x, y);
??? }
?
??? /// <summary>
??? /// 为空处理,必须有
??? /// </summary>
??? public static UDT_Point Null
??? {
??????? get
??????? {
??????????? return new UDT_Point();
??????? }
??? }
?
??? /// <summary>
??? /// 显示函数,必须有
??? /// </summary>
??? /// <returns></returns>
??? public override string ToString()
??? {
?????? ?return string.Format(”({0},{1})”, this.x, this.y);
??? }
?
??? #region INullable Members
??? /// <summary>
??? /// 实现为NULL接口
??? /// </summary>
??? public bool IsNull
??? {
??????? get { return this._isNull; }
??????? set { this._isNull = true; }
??? }
?? ?#endregion
}
?
?
三、部署及调用SQL脚本
?
CREATE TYPE dbo.UDT_Point
EXTERNAL NAME CLRDemoAssemly.[UDT_Point];
?