次の方法で共有


DataReader を使用してデータを取得する

DataReader を使用してデータを取得するには、Command オブジェクトのインスタンスを作成し、DataReader を呼び出してデータ ソースから行を取得してを作成します。 DataReaderは、データ ソースからの結果を効率的に処理する手続き型ロジックを可能にする、バッファーなしのデータ ストリームを提供します。 データがメモリにキャッシュされないため、大量のデータを取得する場合は、 DataReader をお勧めします。

DataReader を使用する例を次に示します。ここで、reader は有効な DataReader を、command は有効な Command オブジェクトを表します。

reader = command.ExecuteReader();
reader = command.ExecuteReader()

クエリ結果から行を取得するには、DataReader.Read メソッドを使用します。 返された行の各列にアクセスするには、その列の名前または序数を DataReader に渡します。 ただし、最適なパフォーマンスを得るために、 DataReader には、ネイティブ データ型 (GetDateTimeGetDoubleGetGuidGetInt32 など) の列値にアクセスできる一連のメソッドが用意されています。 データ プロバイダー固有の DataReader の型指定されたアクセサー メソッドの一覧については、「 OleDbDataReaderSqlDataReader」を参照してください。 基になるデータ型がわかっているときは、型指定されたアクセサー メソッドを使用すると、列の値を取得するときに必要な型変換の量が少なくなります。

次の例では、 DataReader オブジェクトを反復処理し、各行から 2 つの列を返します。

static void HasRows(SqlConnection connection)
{
    using (connection)
    {
        SqlCommand command = new(
          "SELECT CategoryID, CategoryName FROM Categories;",
          connection);
        connection.Open();

        SqlDataReader reader = command.ExecuteReader();

        if (reader.HasRows)
        {
            while (reader.Read())
            {
                Console.WriteLine($"{reader.GetInt32(0)}\t{reader.GetString(1)}");
            }
        }
        else
        {
            Console.WriteLine("No rows found.");
        }
        reader.Close();
    }
}
Private Sub HasRows(ByVal connection As SqlConnection)
    Using connection
        Dim command As SqlCommand = New SqlCommand( _
          "SELECT CategoryID, CategoryName FROM Categories;", _
          connection)
        connection.Open()

        Dim reader As SqlDataReader = command.ExecuteReader()

        If reader.HasRows Then
            Do While reader.Read()
                Console.WriteLine(reader.GetInt32(0) _
                  & vbTab & reader.GetString(1))
            Loop
        Else
            Console.WriteLine("No rows found.")
        End If

        reader.Close()
    End Using
End Sub

DataReader を閉じる

Close オブジェクトの使用が完了したら、常に DataReader メソッドを呼び出します。

Commandに出力パラメーターまたは戻り値が含まれている場合、それらの値はDataReaderが閉じられるまで使用できません。

DataReaderが開いている間、Connectionはその DataReader によって排他的に使用されます。 元のが閉じられるまで、DataReader の作成を含め、Connection のコマンドを実行することはできません。

CloseDispose、またはクラスの メソッド内の他のマネージド オブジェクトでまたはFinalizeを呼び出さないでください。 終了処理では、クラスに直接所有されているアンマネージ リソースだけを解放してください。 クラスがアンマネージ リソースを所有していない場合は、クラス定義に Finalize メソッドを含めないでください。 詳しくは、「ガベージ コレクション」をご覧ください。

NextResult を使用した複数の結果セットの取得

DataReaderが複数の結果セットを返す場合は、NextResult メソッドを呼び出して、結果セットを順番に反復処理します。 SqlDataReader メソッドを使用して、2 つの SELECT ステートメントの結果を処理する ExecuteReader の例を次に示します。

static void RetrieveMultipleResults(SqlConnection connection)
{
    using (connection)
    {
        SqlCommand command = new(
          "SELECT CategoryID, CategoryName FROM dbo.Categories;" +
          "SELECT EmployeeID, LastName FROM dbo.Employees",
          connection);
        connection.Open();

        SqlDataReader reader = command.ExecuteReader();

        while (reader.HasRows)
        {
            Console.WriteLine($"\t{reader.GetName(0)}\t{reader.GetName(1)}");

            while (reader.Read())
            {
                Console.WriteLine($"\t{reader.GetInt32(0)}\t{reader.GetString(1)}");
            }
            reader.NextResult();
        }
    }
}
Private Sub RetrieveMultipleResults(ByVal connection As SqlConnection)
    Using connection
        Dim command As SqlCommand = New SqlCommand( _
          "SELECT CategoryID, CategoryName FROM Categories;" & _
          "SELECT EmployeeID, LastName FROM Employees", connection)
        connection.Open()

        Dim reader As SqlDataReader = command.ExecuteReader()

        Do While reader.HasRows
            Console.WriteLine(vbTab & reader.GetName(0) _
              & vbTab & reader.GetName(1))

            Do While reader.Read()
                Console.WriteLine(vbTab & reader.GetInt32(0) _
                  & vbTab & reader.GetString(1))
            Loop

            reader.NextResult()
        Loop
    End Using
End Sub

DataReader からスキーマ情報を取得する

DataReaderが開いている間は、GetSchemaTable メソッドを使用して、現在の結果セットに関するスキーマ情報を取得できます。 GetSchemaTable は、現在の結果セットのスキーマ情報を含む行と列が設定された DataTable オブジェクトを返します。 DataTableには、結果セットの列ごとに 1 つの行が含まれています。 スキーマ テーブルの各列は、結果セットの行で返される列のプロパティにマップされます。ここで、 ColumnName はプロパティの名前、列の値はプロパティの値です。 DataReader のスキーマ情報を出力する例を次に示します。

static void GetSchemaInfo(SqlConnection connection)
{
    using (connection)
    {
        SqlCommand command = new(
          "SELECT CategoryID, CategoryName FROM Categories;",
          connection);
        connection.Open();

        SqlDataReader reader = command.ExecuteReader();
        DataTable schemaTable = reader.GetSchemaTable();

        foreach (DataRow row in schemaTable.Rows)
        {
            foreach (DataColumn column in schemaTable.Columns)
            {
                Console.WriteLine(string.Format("{0} = {1}",
                   column.ColumnName, row[column]));
            }
        }
    }
}
Private Sub GetSchemaInfo(ByVal connection As SqlConnection)
    Using connection
        Dim command As SqlCommand = New SqlCommand( _
          "SELECT CategoryID, CategoryName FROM Categories;", _
          connection)
        connection.Open()

        Dim reader As SqlDataReader = command.ExecuteReader()
        Dim schemaTable As DataTable = reader.GetSchemaTable()

        Dim row As DataRow
        Dim column As DataColumn

        For Each row In schemaTable.Rows
            For Each column In schemaTable.Columns
                Console.WriteLine(String.Format("{0} = {1}", _
                  column.ColumnName, row(column)))
            Next
            Console.WriteLine()
        Next
        reader.Close()
    End Using
End Sub

OLE DB のチャプターの使用

階層行セットまたは章 (OLE DB 型 DBTYPE_HCHAPTER、ADO 型 adChapter) は、 OleDbDataReaderを使用して取得できます。 章を含むクエリが DataReader として返されると、その章はその DataReader の列として返され、 DataReader オブジェクトとして公開されます。

ADO.NET DataSet は、テーブル間の親子リレーションシップを使用して階層的な行セットを表すためにも使用できます。 詳細については、「 DataSets、DataTables、DataViews」を参照してください。

次のコード例では、MSDataShape プロバイダーを使用して、顧客の一覧で各顧客の注文の章列を生成します。

Using connection As OleDbConnection = New OleDbConnection(
    "Provider=MSDataShape;Data Provider=SQLOLEDB;" &
    "Data Source=localhost;Integrated Security=SSPI;Initial Catalog=northwind")

    Using custCMD As OleDbCommand = New OleDbCommand(
        "SHAPE {SELECT CustomerID, CompanyName FROM Customers} " &
        "APPEND ({SELECT CustomerID, OrderID FROM Orders} AS CustomerOrders " &
        "RELATE CustomerID TO CustomerID)", connection)

        connection.Open()

        Using custReader As OleDbDataReader = custCMD.ExecuteReader()

            Do While custReader.Read()
                Console.WriteLine("Orders for " & custReader.GetString(1))
                ' custReader.GetString(1) = CompanyName

                Using orderReader As OleDbDataReader = custReader.GetValue(2)
                    ' custReader.GetValue(2) = Orders chapter as DataReader

                    Do While orderReader.Read()
                        Console.WriteLine(vbTab & orderReader.GetInt32(1))
                        ' orderReader.GetInt32(1) = OrderID
                    Loop
                    orderReader.Close()
                End Using
            Loop
            ' Make sure to always close readers and connections.
            custReader.Close()
        End Using
    End Using
End Using
using (OleDbConnection connection = new OleDbConnection(
    "Provider=MSDataShape;Data Provider=SQLOLEDB;" +
    "Data Source=localhost;Integrated Security=SSPI;Initial Catalog=northwind"))
{
    using (OleDbCommand custCMD = new OleDbCommand(
        "SHAPE {SELECT CustomerID, CompanyName FROM Customers} " +
        "APPEND ({SELECT CustomerID, OrderID FROM Orders} AS CustomerOrders " +
        "RELATE CustomerID TO CustomerID)", connection))
    {
        connection.Open();

        using (OleDbDataReader custReader = custCMD.ExecuteReader())
        {

            while (custReader.Read())
            {
                Console.WriteLine("Orders for " + custReader.GetString(1));
                // custReader.GetString(1) = CompanyName

                using (OleDbDataReader orderReader = (OleDbDataReader)custReader.GetValue(2))
                {
                    // custReader.GetValue(2) = Orders chapter as DataReader

                    while (orderReader.Read())
                        Console.WriteLine("\t" + orderReader.GetInt32(1));
                    // orderReader.GetInt32(1) = OrderID
                    orderReader.Close();
                }
            }
            // Make sure to always close readers and connections.
            custReader.Close();
        }
    }
}

Oracle REF CURSOR を使用して結果を返す

.NET Framework Data Provider for Oracle では、Oracle REF CURSOR を使用してクエリ結果を返す機能がサポートされています。 Oracle REF CURSOR が OracleDataReaderとして返されます。

OracleDataReader メソッドを使用して、Oracle REF CURSOR を表すExecuteReader オブジェクトを取得できます。 OracleCommand は、DataSet を埋めるために使用される OracleDataAdapterSelectCommand として、1つ以上の Oracle REF CURSOR を返すように指定することもできます。

Oracle データ ソースから返された REF CURSOR にアクセスするには、クエリのOracleCommandを作成し、REF CURSOR を参照する出力パラメーターをParametersOracleCommand コレクションに追加します。 パラメーターの名前は、クエリ内の REF CURSOR パラメーターの名前と一致する必要があります。 パラメーターの型を OracleType.Cursor に設定します。 OracleCommand.ExecuteReader()OracleCommand メソッドは、REF CURSOR のOracleDataReaderを返します。

OracleCommandが複数の REF CURSORS を返す場合は、複数の出力パラメーターを追加します。 OracleCommand.ExecuteReader() メソッドを呼び出すことで、さまざまな REF CURSOR にアクセスできます。 ExecuteReader()の呼び出しは、最初の REF CURSOR を参照するOracleDataReaderを返します。 その後、 OracleDataReader.NextResult() メソッドを呼び出して、後続の REF CURSOR にアクセスできます。 OracleCommand.Parameters コレクション内のパラメーターは、名前によって REF CURSOR 出力パラメーターと一致しますが、OracleDataReaderは、Parameters コレクションに追加された順序でそれらにアクセスします。

たとえば、次の Oracle パッケージとパッケージ本文について考えてみます。

CREATE OR REPLACE PACKAGE CURSPKG AS
  TYPE T_CURSOR IS REF CURSOR;
  PROCEDURE OPEN_TWO_CURSORS (EMPCURSOR OUT T_CURSOR,
    DEPTCURSOR OUT T_CURSOR);
END CURSPKG;

CREATE OR REPLACE PACKAGE BODY CURSPKG AS
  PROCEDURE OPEN_TWO_CURSORS (EMPCURSOR OUT T_CURSOR,
    DEPTCURSOR OUT T_CURSOR)
  IS
  BEGIN
    OPEN EMPCURSOR FOR SELECT * FROM DEMO.EMPLOYEE;
    OPEN DEPTCURSOR FOR SELECT * FROM DEMO.DEPARTMENT;
  END OPEN_TWO_CURSORS;
END CURSPKG;

次のコードでは、OracleCommand コレクションにOracleType.Cursor型の 2 つのパラメーターを追加して、前の Oracle パッケージから REF CURSOR を返すOracleCommand.Parametersを作成します。

Dim cursCmd As OracleCommand = New OracleCommand("CURSPKG.OPEN_TWO_CURSORS", oraConn)
cursCmd.Parameters.Add("EMPCURSOR", OracleType.Cursor).Direction = ParameterDirection.Output
cursCmd.Parameters.Add("DEPTCURSOR", OracleType.Cursor).Direction = ParameterDirection.Output
OracleCommand cursCmd = new OracleCommand("CURSPKG.OPEN_TWO_CURSORS", oraConn);
cursCmd.Parameters.Add("EMPCURSOR", OracleType.Cursor).Direction = ParameterDirection.Output;
cursCmd.Parameters.Add("DEPTCURSOR", OracleType.Cursor).Direction = ParameterDirection.Output;

次のコードは、Read()NextResult() メソッドと OracleDataReader メソッドを使用して、前のコマンドの結果を返します。 REF CURSOR パラメーターは順番に返されます。

oraConn.Open()

Dim cursCmd As OracleCommand = New OracleCommand("CURSPKG.OPEN_TWO_CURSORS", oraConn)
cursCmd.CommandType = CommandType.StoredProcedure
cursCmd.Parameters.Add("EMPCURSOR", OracleType.Cursor).Direction = ParameterDirection.Output
cursCmd.Parameters.Add("DEPTCURSOR", OracleType.Cursor).Direction = ParameterDirection.Output

Dim reader As OracleDataReader = cursCmd.ExecuteReader()

Console.WriteLine(vbCrLf & "Emp ID" & vbTab & "Name")

Do While reader.Read()
  Console.WriteLine("{0}" & vbTab & "{1}, {2}", reader.GetOracleNumber(0), reader.GetString(1), reader.GetString(2))
Loop

reader.NextResult()

Console.WriteLine(vbCrLf & "Dept ID" & vbTab & "Name")

Do While reader.Read()
  Console.WriteLine("{0}" & vbTab & "{1}", reader.GetOracleNumber(0), reader.GetString(1))
Loop
' Make sure to always close readers and connections.
reader.Close()
oraConn.Close()
oraConn.Open();

OracleCommand cursCmd = new OracleCommand("CURSPKG.OPEN_TWO_CURSORS", oraConn);
cursCmd.CommandType = CommandType.StoredProcedure;
cursCmd.Parameters.Add("EMPCURSOR", OracleType.Cursor).Direction = ParameterDirection.Output;
cursCmd.Parameters.Add("DEPTCURSOR", OracleType.Cursor).Direction = ParameterDirection.Output;

OracleDataReader reader = cursCmd.ExecuteReader();

Console.WriteLine("\nEmp ID\tName");

while (reader.Read())
  Console.WriteLine("{0}\t{1}, {2}", reader.GetOracleNumber(0), reader.GetString(1), reader.GetString(2));

reader.NextResult();

Console.WriteLine("\nDept ID\tName");

while (reader.Read())
  Console.WriteLine("{0}\t{1}", reader.GetOracleNumber(0), reader.GetString(1));
// Make sure to always close readers and connections.
reader.Close();
oraConn.Close();

次の例では、前のコマンドを使用して、Oracle パッケージの結果を DataSet に設定します。

Dim ds As DataSet = New DataSet()

Dim adapter As OracleDataAdapter = New OracleDataAdapter(cursCmd)
adapter.TableMappings.Add("Table", "Employees")
adapter.TableMappings.Add("Table1", "Departments")

adapter.Fill(ds)
DataSet ds = new DataSet();

OracleDataAdapter adapter = new OracleDataAdapter(cursCmd);
adapter.TableMappings.Add("Table", "Employees");
adapter.TableMappings.Add("Table1", "Departments");

adapter.Fill(ds);

OverflowException を回避するには、値をDataRowに格納する前に、Oracle NUMBER 型から有効な .NET Framework 型への変換も処理することをお勧めします。 FillError イベントを使用して、OverflowExceptionが発生したかどうかを判断できます。 FillError イベントの詳細については、「DataAdapter イベントの処理」を参照してください。

こちらも参照ください