检索 ADO.NET 中的用户定义的类型(UDT)数据

适用范围:SQL Server

若要在客户端上创建用户定义的类型(UDT),在 SQL Server 数据库中注册为 UDT 的程序集必须可供客户端应用程序使用。 UDT 程序集可位于该应用程序的相同目录中,也可以位于全局程序集缓存 (GAC) 中。 还可以在项目中设置对该程序集的引用。

在 ADO.NET 中使用 UDT 的要求

在 SQL Server 中加载的程序集和客户端上的程序集必须兼容才能在客户端上创建 UDT。 对于使用 Native 序列化格式定义的 UDT,程序集必须在结构上兼容。 对于使用 UserDefined 格式定义的程序集,程序集必须在客户端上可用。

在客户端上不需要 UDT 程序集的副本,以便从表中的 UDT 列检索原始数据。

注意

如果 UDT 版本不匹配或其他问题,SqlClient 可能无法加载 UDT。 在这种情况下,请使用常规故障排除机制来确定调用应用程序找不到包含 UDT 的程序集的原因。 有关详细信息,请参阅 使用托管调试助手诊断错误

使用 SqlDataReader 访问 UDT

可以从客户端代码使用 System.Data.SqlClient.SqlDataReader 来检索包含 UDT 列的结果集,该列作为对象的实例公开。

示例

此示例演示如何使用 Main 方法创建新的 SqlDataReader 对象。 下面的操作是在代码示例中执行的:

  1. Main 方法创建一个新的 SqlDataReader 对象,并从 Points 表中检索值,该表具有名为 Point 的 UDT 列。

  2. Point UDT 公开定义为整数的 X 和 Y 坐标。

  3. UDT 定义 Distance 方法和 GetDistanceFromXY 方法。

  4. 示例代码检索主键列和 UDT 列的值,以便显示 UDT 的功能。

  5. 示例代码调用 Point.DistancePoint.GetDistanceFromXY 方法。

  6. 结果将显示在控制台窗口中。

注意

应用程序必须已具有对 UDT 程序集的引用。

using System;
using System.Data.Sql;
using System.Data.SqlClient;

namespace Microsoft.Samples.SqlServer
{
    class ReadPoints
    {
        static void Main()
        {
            string connectionString = GetConnectionString();
            using (SqlConnection cnn = new SqlConnection(connectionString))
            {
                cnn.Open();
                SqlCommand cmd = new SqlCommand(
                    "SELECT ID, Pnt FROM dbo.Points", cnn);
                SqlDataReader rdr = cmd.ExecuteReader();

                while (rdr.Read())
                {
                    // Retrieve the value of the Primary Key column
                    int id = rdr.GetInt32(0);

                    // Retrieve the value of the UDT
                    Point pnt = (Point)rdr[1];

                    // You can also use GetSqlValue and GetValue
                    // Point pnt = (Point)rdr.GetSqlValue(1);
                    // Point pnt = (Point)rdr.GetValue(1);

                    Console.WriteLine(
                        "ID={0} Point={1} X={2} Y={3} DistanceFromXY={4} Distance={5}",
                        id, pnt, pnt.X, pnt.Y, pnt.DistanceFromXY(1, 9), pnt.Distance());
                }
                rdr.Close();
                Console.WriteLine("done");
            }
            static private string GetConnectionString()
            {
                // To avoid storing the connection string in your code,
                // you can retrieve it from a configuration file.
                return "Data Source=(local);Initial Catalog=AdventureWorks2022"
                       + "Integrated Security=SSPI";
            }
        }
    }
}

将 UDT 绑定为字节

在某些情况下,可能需要从 UDT 列检索原始数据。 可能类型在本地不可用,或者不希望实例化 UDT 的实例。 可以使用 SqlDataReaderGetBytes 方法将原始字节读取到字节数组中。 该方法从指定的列偏移量将字节流作为数组从指定缓冲区偏移量开始读入缓冲区。 另一个选项是使用其中一个 GetSqlBytesGetSqlBinary 方法,并在单个操作中读取所有内容。 在任一情况下,都不会实例化 UDT 对象,因此无需在客户端程序集中设置对 UDT 的引用。

示例

此示例演示如何使用 SqlDataReaderPoint 数据作为原始字节检索到字节数组中。 该代码使用 System.Text.StringBuilder 将原始字节转换为要显示在控制台窗口中的字符串表示形式。

using System;
using System.Data.Sql;
using System.Data.SqlClient;
using System.Data.SqlTypes;
using System.Text;

class GetRawBytes
{
    static void Main()
    {
        string connectionString = GetConnectionString();
        using (SqlConnection cnn = new SqlConnection(connectionString))
        {
            cnn.Open();
            SqlCommand cmd = new SqlCommand("SELECT ID, Pnt FROM dbo.Points", cnn);
            SqlDataReader rdr = cmd.ExecuteReader();

            while (rdr.Read())
            {
                // Retrieve the value of the Primary Key column
                int id = rdr.GetInt32(0);

                // Retrieve the raw bytes into a byte array
                byte[] buffer = new byte[32];
                long byteCount = rdr.GetBytes(1, 0, buffer, 0, 32);

                // Format and print bytes
                StringBuilder str = new StringBuilder();
                str.AppendFormat("ID={0} Point=", id);

                for (int i = 0; i < byteCount; i++)
                    str.AppendFormat("{0:x}", buffer[i]);
                Console.WriteLine(str.ToString());
            }
            rdr.Close();
            Console.WriteLine("done");
        }
    static private string GetConnectionString()
    {
        // To avoid storing the connection string in your code,
        // you can retrieve it from a configuration file.
        return "Data Source=(local);Initial Catalog=AdventureWorks2022"
            + "Integrated Security=SSPI";
    }
  }
}

使用 GetSqlBytes 的示例

此示例演示如何使用 GetSqlBytes 方法在单个操作中以原始字节的形式检索 Point 数据。 该代码使用 StringBuilder 将原始字节转换为要显示在控制台窗口中的字符串表示形式。

using System;
using System.Data.Sql;
using System.Data.SqlClient;
using System.Data.SqlTypes;
using System.Text;

class GetRawBytes
{
    static void Main()
    {
         string connectionString = GetConnectionString();
        using (SqlConnection cnn = new SqlConnection(connectionString))
        {
            cnn.Open();
            SqlCommand cmd = new SqlCommand(
                "SELECT ID, Pnt FROM dbo.Points", cnn);
            SqlDataReader rdr = cmd.ExecuteReader();

            while (rdr.Read())
            {
                // Retrieve the value of the Primary Key column
                int id = rdr.GetInt32(0);

                // Use SqlBytes to retrieve raw bytes
                SqlBytes sb = rdr.GetSqlBytes(1);
                long byteCount = sb.Length;

                // Format and print bytes
                StringBuilder str = new StringBuilder();
                str.AppendFormat("ID={0} Point=", id);

                for (int i = 0; i < byteCount; i++)
                    str.AppendFormat("{0:x}", sb[i]);
                Console.WriteLine(str.ToString());
            }
            rdr.Close();
            Console.WriteLine("done");
        }
    static private string GetConnectionString()
    {
        // To avoid storing the connection string in your code,
        // you can retrieve it from a configuration file.
        return "Data Source=(local);Initial Catalog=AdventureWorks2022"
            + "Integrated Security=SSPI";
    }
  }
}

使用 UDT 参数

可以在 ADO.NET 代码中将 UDT 作为输入参数和输出参数使用。

在查询参数中使用 UDT

System.Data.SqlClient.SqlCommand 对象设置 SqlParameter 时,UDT 可用作参数值。 SqlParameter 对象的 SqlDbType.Udt 枚举用于指示参数在调用 Add 方法到 Parameters 集合时为 UDT。 SqlCommand 对象的 UdtTypeName 属性用于使用 <database>.<schema_name>.<object_name> 语法在数据库中指定 UDT 的完全限定名称。 应使用完全限定的名称来避免代码中的歧义。

UDT 程序集的本地副本必须对客户端项目可用。

示例

此示例中的代码创建 SqlCommandSqlParameter 对象,以将数据插入表中的 UDT 列中。 该代码使用 SqlDbType.Udt 枚举来指定数据类型,SqlParameter 对象的 UdtTypeName 属性指定数据库中 UDT 的完全限定名称。

using System;
using System.Data;
using System.Data.Sql;
using System.Data.SqlClient;

class Class1
{
static void Main()
{
  string ConnectionString = GetConnectionString();
     using (SqlConnection cnn = new SqlConnection(ConnectionString))
     {
       SqlCommand cmd = cnn.CreateCommand();
       cmd.CommandText =
         "INSERT INTO dbo.Points (Pnt) VALUES (@Point)";
       cmd.CommandType = CommandType.Text;

       SqlParameter param = new SqlParameter("@Point", SqlDbType.Udt);       param.UdtTypeName = "TestPoint.dbo.Point";       param.Direction = ParameterDirection.Input;       param.Value = new Point(5, 6);       cmd.Parameters.Add(param);

       cnn.Open();
       cmd.ExecuteNonQuery();
       Console.WriteLine("done");
     }
    static private string GetConnectionString()
    {
        // To avoid storing the connection string in your code,
        // you can retrieve it from a configuration file.
        return "Data Source=(local);Initial Catalog=AdventureWorks2022"
            + "Integrated Security=SSPI";
    }
  }
}