创建用户定义类型

若要创建能够在 SQL Server 中安装的用户定义类型 (UDT),必须首先用一种支持的 .NET Framework 编程语言(例如 Visual C# 或 Visual Basic,该语言符合创建 UDT 的规范)创建一个类。然后,可以将该类编译为可以在 SQL Server 中加载的动态链接库 (DLL)。还可以使用 Visual Studio 创建和部署 UDT。

在 SQL Server 中,默认情况下,执行公共语言运行时 (CLR) 代码的能力设置为 OFF。通过使用 sp_configure 系统存储过程,可以启用 CLR,如以下 Transact-SQL 语句所示:

sp_configure 'clr enabled', 1
Reconfigure

有关详细信息,请参阅 使用 CLR 用户定义类型

本节涉及的主题

示例

以下代码列表定义了 Point UDT,用户定义类型编码中对此进行了详细介绍。

通过安装 CLR 示例,可以获得在本节中讨论的其他示例的完整代码列表。有关安装这些示例的说明,请参阅安装 SQL Server 示例和示例数据库的注意事项

C#

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

[Serializable]
[Microsoft.SqlServer.Server.SqlUserDefinedType(Format.Native,
     IsByteOrdered=true, ValidationMethodName = "ValidatePoint")]
public struct Point : INullable
{
    private bool is_Null;
    private Int32 _x;
    private Int32 _y;

    public bool IsNull
    {
        get
        {
            return (is_Null);
        }
    }

    public static Point Null
    {
        get
        {
            Point pt = new Point();
            pt.is_Null = true;
            return pt;
        }
    }

    // Use StringBuilder to provide string representation of UDT.
    public override string ToString()
    {
        // Since InvokeIfReceiverIsNull defaults to 'true'
        // this test is unneccesary if Point is only being called
        // from SQL.
        if (this.IsNull)
            return "NULL";
        else
        {
            StringBuilder builder = new StringBuilder();
            builder.Append(_x);
            builder.Append(",");
            builder.Append(_y);
            return builder.ToString();
        }
    }

    [SqlMethod(OnNullCall = false)]
    public static Point Parse(SqlString s)
    {
        // With OnNullCall=false, this check is unnecessary if 
        // Point only called from SQL.
        if (s.IsNull)
            return Null;

        // Parse input string to separate out points.
        Point pt = new Point();
        string[] xy = s.Value.Split(",".ToCharArray());
        pt.X = Int32.Parse(xy[0]);
        pt.Y = Int32.Parse(xy[1]);

        // Call ValidatePoint to enforce validation
        // for string conversions.
        if (!pt.ValidatePoint()) 
            throw new ArgumentException("Invalid XY coordinate values.");
        return pt;
    }

    // X and Y coordinates exposed as properties.
    public Int32 X
    {
        get
        {
            return this._x;
        }
        // Call ValidatePoint to ensure valid range of Point values.
        set 
        {
            Int32 temp = _x;
            _x = value;
            if (!ValidatePoint())
            {
                _x = temp;
                throw new ArgumentException("Invalid X coordinate value.");
            }
        }
    }

    public Int32 Y
    {
        get
        {
            return this._y;
        }
        set
        {
            Int32 temp = _y;
            _y = value;
            if (!ValidatePoint())
            {
                _y = temp;
                throw new ArgumentException("Invalid Y coordinate value.");
            }
        }
    }

    // Validation method to enforce valid X and Y values.
    private bool ValidatePoint()
    {
        // Allow only zero or positive integers for X and Y coordinates.
        if ((_x >= 0) && (_y >= 0))
        {
            return true;
        }
        else
        {
            return false;
        }
    }

    // Distance from 0 to Point method.
    [SqlMethod(OnNullCall = false)]
    public Double Distance()
    {
        return DistanceFromXY(0, 0);
    }

    // Distance from Point to the specified point method.
    [SqlMethod(OnNullCall = false)]
    public Double DistanceFrom(Point pFrom)
    {
        return DistanceFromXY(pFrom.X, pFrom.Y);
    }

    // Distance from Point to the specified x and y values method.
    [SqlMethod(OnNullCall = false)]
    public Double DistanceFromXY(Int32 iX, Int32 iY)
    {
        return Math.Sqrt(Math.Pow(iX - _x, 2.0) + Math.Pow(iY - _y, 2.0));
    }
}

Visual Basic

Option Explicit On
Option Strict On

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

<Serializable(), SqlUserDefinedTypeAttribute(Format.Native, _
  IsByteOrdered:=True, _
  ValidationMethodName:="ValidatePoint")> _
  Public Structure Point
    Implements INullable

    Private is_Null As Boolean
    Private _x As Int32
    Private _y As Int32

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

    Public Shared ReadOnly Property Null() As Point
        Get
            Dim pt As New Point
            pt.is_Null = True
            Return (pt)
        End Get
    End Property

    ' Use StringBuilder to provide string representation of UDT.
    Public Overrides Function ToString() As String
        ' Since InvokeIfReceiverIsNull defaults to 'true'
        ' this test is unneccesary if Point is only being called
        ' from SQL.
        If Me.IsNull Then
            Return "NULL"
        Else
            Dim builder As StringBuilder = New StringBuilder
            builder.Append(_x)
            builder.Append(",")
            builder.Append(_y)
            Return builder.ToString
        End If
    End Function

    <SqlMethod(OnNullCall:=False)> _
    Public Shared Function Parse(ByVal s As SqlString) As Point
        ' With OnNullCall=False, this check is unnecessary if
        ' Point only being called from SQL.
        If s.IsNull Then
            Return Null
        End If

        ' Parse input string here to separate out points.
        Dim pt As New Point()
        Dim xy() As String = s.Value.Split(",".ToCharArray())
        pt.X = Int32.Parse(xy(0))
        pt.Y = Int32.Parse(xy(1))

        ' Call ValidatePoint to enforce validation
        ' for string conversions.
        If Not pt.ValidatePoint() Then
            Throw New ArgumentException("Invalid XY coordinate values.")
        End If
        Return pt
    End Function

    ' X and Y coordinates are exposed as properties.
    Public Property X() As Int32
        Get
            Return (Me._x)
        End Get

        Set(ByVal Value As Int32)
            Dim temp As Int32 = _x
            _x = Value
            If Not ValidatePoint() Then
                _x = temp
                Throw New ArgumentException("Invalid X coordinate value.")
            End If
        End Set
    End Property

    Public Property Y() As Int32
        Get
            Return (Me._y)
        End Get

        Set(ByVal Value As Int32)
            Dim temp As Int32 = _y
            _y = Value
            If Not ValidatePoint() Then
                _y = temp
                Throw New ArgumentException("Invalid Y coordinate value.")
            End If
        End Set
    End Property

    ' Validation method to enforce valid X and Y values.
    Private Function ValidatePoint() As Boolean
        ' Allow only zero or positive integers for X and Y coordinates.
        If (_x >= 0) And (_y >= 0) Then
            Return True
        Else
            Return False
        End If
    End Function

    ' Distance from 0 to Point method.
    <SqlMethod(OnNullCall:=False)> _
  Public Function Distance() As Double
        Return DistanceFromXY(0, 0)
    End Function

    ' Distance from Point to the specified point method.
    <SqlMethod(OnNullCall:=False)> _
    Public Function DistanceFrom(ByVal pFrom As Point) As Double
        Return DistanceFromXY(pFrom.X, pFrom.Y)
    End Function

    ' Distance from Point to the specified x and y values method.
    <SqlMethod(OnNullCall:=False)> _
    Public Function DistanceFromXY(ByVal ix As Int32, ByVal iy As Int32) _
        As Double
        Return Math.Sqrt(Math.Pow(ix - _x, 2.0) + Math.Pow(iy - _y, 2.0))
    End Function
End Structure

请参阅

概念