UDT データの取得

クライアント側で UDT (ユーザー定義型) を作成するには、SQL Server データベースに UDT として登録されたアセンブリをクライアント アプリケーションで使用できるようにしておく必要があります。この UDT アセンブリは、アプリケーションと同じディレクトリまたは GAC (グローバル アセンブリ キャッシュ) に配置できます。また、プロジェクト内で、このアセンブリへの参照を設定することもできます。

ADO.NET で UDT を使用するための要件

クライアント側で UDT を作成するには、SQL Server に読み込まれたアセンブリとクライアント側に存在するアセンブリとの間に互換性がなくてはなりません。Native シリアル化形式で定義した UDT の場合は、アセンブリの構造に互換性が必要です。UserDefined 形式で定義したアセンブリの場合は、そのアセンブリをクライアント側で使用できる必要があります。

テーブルの UDT 列からデータをそのまま取得するために、クライアントに UDT アセンブリをコピーする必要はありません。

注意注意

UDT のバージョンが一致しない場合や他の問題が発生した場合、SqlClient では UDT を読み込めないことがあります。この場合、通常のトラブルシューティング メカニズムを使用して、呼び出し元のアプリケーションで UDT を含むアセンブリが検出されない原因を特定します。詳細については、.NET Framework の「Diagnosing Errors with Managed Debugging Assistants」を参照してください。

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.Distance メソッドと Point.GetDistanceFromXY メソッドを呼び出します。

  6. 結果はコンソール ウィンドウに表示されます。

注意注意

アプリケーションでは、事前に UDT アセンブリへの参照が設定されている必要があります。

Option Explicit On
Option Strict On

Imports System
Imports System.Data.Sql
Imports System.Data.SqlClient

Module ReadPoints
    Sub Main()
        Dim connectionString As String = GetConnectionString()
        Using cnn As New SqlConnection(connectionString)
            cnn.Open()
            Dim cmd As New SqlCommand( _
             "SELECT ID, Pnt FROM dbo.Points", cnn)
            Dim rdr As SqlDataReader
            rdr = cmd.ExecuteReader

            While rdr.Read()
                ' Retrieve the value of the Primary Key column
                Dim id As Int32 = rdr.GetInt32(0)

                ' Retrieve the value of the UDT
                Dim pnt As Point = CType(rdr(1), Point)

             ' You can also use GetSqlValue and GetValue
             ' Dim pnt As Point = CType(rdr.GetSqlValue(1), Point)
             ' Dim pnt As Point = CType(rdr.GetValue(1), Point)

                ' Print values
                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())
            End While
            rdr.Close()
            Console.WriteLine("done")
        End Using
    End Sub
    Private Function GetConnectionString() As String
        ' To avoid storing the connection string in your code,  
        ' you can retrieve it from a configuration file.
        Return "Data Source=(local);Initial Catalog=AdventureWorks;" _
         & "Integrated Security=SSPI;"
    End Function
End Module
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=AdventureWorks;"
        + "Integrated Security=SSPI";
  }
}

バイト型としての UDT のバインド

場合によっては、UDT 列からそのままデータを取得する必要が生じることもあります。たとえば、型がローカルに存在しない場合や、UDT のインスタンスを作成したくない場合などです。SqlDataReader オブジェクトの GetBytes メソッドを使用すると、バイト列をそのままバイト配列に読み取ることができます。このメソッドでは、バイトのストリームを、指定した列オフセットから、指定したバッファ オフセットから始まる配列のバッファに読み取ることができます。別の方法として、GetSqlBytes メソッドか GetSqlBinary メソッドのいずれかを使用して、すべての内容を 1 回の操作で読み取ることもできます。どちらの場合も、UDT オブジェクトのインスタンスが作成されることはないので、クライアントのアセンブリで UDT への参照を設定する必要はありません。

この例では、SqlDataReader オブジェクトを使用して、Point データをそのままバイト列として、バイト配列に取得する方法を示します。このコードでは、System.Text.StringBuilder を使用して、生のバイト列をコンソール ウィンドウに表示する文字列形式に変換します。

Option Explicit On
Option Strict On

Imports System
Imports System.Data.Sql
Imports System.Data.SqlClient
Imports System.Data.SqlTypes
Imports System.Text

Module GetRawBytes
    Sub Main()
        Dim connectionString As String = GetConnectionString()
        Using cnn As New SqlConnection(connectionString)
            cnn.Open()
            Dim cmd As New SqlCommand( _
             "SELECT ID, Pnt FROM dbo.Points", cnn)
            Dim rdr As SqlDataReader
            rdr = cmd.ExecuteReader

            While rdr.Read()

                ' Retrieve the value of the Primary Key column
                Dim id As Int32 = rdr.GetInt32(0)

                ' Retrieve the raw bytes into a byte array
                Dim buffer(31) As Byte
                Dim byteCount As Integer = _
                 CInt(rdr.GetBytes(1, 0, buffer, 0, 31))

                ' Format and print bytes 
                Dim str As New StringBuilder
                str.AppendFormat("ID={0} Point=", id)

                Dim i As Integer
                For i = 0 To (byteCount - 1)
                    str.AppendFormat("{0:x}", buffer(i))
                Next
                Console.WriteLine(str.ToString)

            End While
            rdr.Close()
            Console.WriteLine("done")
        End Using
    End Sub
    Private Function GetConnectionString() As String
        ' To avoid storing the connection string in your code,  
        ' you can retrieve it from a configuration file.
        Return "Data Source=(local);Initial Catalog=AdventureWorks;" _
           & "Integrated Security=SSPI;"
    End Function
End Module
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=AdventureWorks;"
            + "Integrated Security=SSPI";
    }
  }
}

GetSqlBytes メソッドの使用例

この例では、GetSqlBytes メソッドを使用して、1 回の操作で Point データをバイト列としてそのまま取得する方法を示します。このコードでは、StringBuilder を使用して、生のバイト列をコンソール ウィンドウに表示する文字列形式に変換します。

Option Explicit On
Option Strict On

Imports System
Imports System.Data.Sql
Imports System.Data.SqlClient
Imports System.Data.SqlTypes
Imports System.Text

Module GetRawBytes
    Sub Main()
        Dim connectionString As String = GetConnectionString()
        Using cnn As New SqlConnection(connectionString)
            cnn.Open()
            Dim cmd As New SqlCommand( _
             "SELECT ID, Pnt FROM dbo.Points", cnn)
            Dim rdr As SqlDataReader
            rdr = cmd.ExecuteReader

            While rdr.Read()
                ' Retrieve the value of the Primary Key column
                Dim id As Int32 = rdr.GetInt32(0)

                ' Use SqlBytes to retrieve raw bytes
                Dim sb As SqlBytes = rdr.GetSqlBytes(1)
                Dim byteCount As Long = sb.Length

                ' Format and print bytes 
                Dim str As New StringBuilder
                str.AppendFormat("ID={0} Point=", id)

                Dim i As Integer
                For i = 0 To (byteCount - 1)
                    str.AppendFormat("{0:x}", sb(i))
                Next
                Console.WriteLine(str.ToString)

            End While
            rdr.Close()
            Console.WriteLine("done")
        End Using
    End Sub
    Private Function GetConnectionString() As String
        ' To avoid storing the connection string in your code,  
        ' you can retrieve it from a configuration file.
        Return "Data Source=(local);Initial Catalog=AdventureWorks;" _
           & "Integrated Security=SSPI;"
    End Function
End Module
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=AdventureWorks;"
            + "Integrated Security=SSPI";
    }
  }
}

UDT パラメータを使用した作業

ADO.NET コードでは、UDT は入力パラメータと出力パラメータのどちらとしても使用することができます。

クエリ パラメータでの UDT の使用

UDT は、System.Data.SqlClient.SqlCommand オブジェクトの SqlParameter を設定する際にパラメータ値として使用できます。SqlParameter オブジェクトの SqlDbType.Udt 列挙値は、Parameters コレクションに対して Add メソッドを呼び出す際、パラメータが UDT であることを示すために使用します。SqlCommand オブジェクトの UdtTypeName プロパティは、database.schema_name.object_name 構文を使用して、データベースの UDT の完全修飾名を指定する際に使用します。必須ではありませんが、完全修飾名を使用すると、コードを明確にすることができます。

注意注意

クライアント プロジェクトが、UDT アセンブリのローカル コピーを使用できることが前提です。

この例のコードでは、SqlCommand オブジェクトと SqlParameter オブジェクトを使用して、テーブルの UDT 列にデータを挿入します。このコードでは、SqlDbType.Udt 列挙値を使用してデータ型を指定し、SqlParameter オブジェクトの UdtTypeName プロパティを使用してデータベースの UDT の完全修飾名を指定します。

Option Explicit On
Option Strict On

Imports System
Imports system.Data
Imports System.Data.Sql
Imports System.Data.SqlClient

Module Module1

  Sub Main()
    Dim ConnectionString As String = GetConnectionString()
    Dim cnn As New SqlConnection(ConnectionString)
    Using cnn
      Dim cmd As SqlCommand = cnn.CreateCommand()
      cmd.CommandText = "INSERT INTO dbo.Points (Pnt) VALUES (@Point)"
      cmd.CommandType = CommandType.Text

      Dim param As 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")
    End Using
  End Sub
    Private Function GetConnectionString() As String
        ' To avoid storing the connection string in your code,  
        ' you can retrieve it from a configuration file.
        Return "Data Source=(local);Initial Catalog=AdventureWorks;" _
           & "Integrated Security=SSPI;"
    End Function
End Module
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=AdventureWorks;"
            + "Integrated Security=SSPI";
    }
  }
}

関連項目

その他の技術情報