DataReader を使用してデータを取得するRetrieve data using a DataReader

DataReader を使用してデータを取得するには、Command オブジェクトのインスタンスを作成した後、Command.ExecuteReader を呼び出して DataReader を作成し、データ ソースから行を取得します。To retrieve data using a DataReader, create an instance of the Command object, and then create a DataReader by calling Command.ExecuteReader to retrieve rows from a data source. DataReader では、手続きロジックがデータ ソースからの結果を順番に効率的に処理できるようにするバッファリングされないデータ ストリームが提供されます。The DataReader provides an unbuffered stream of data that allows procedural logic to efficiently process results from a data source sequentially. DataReader はデータをメモリにキャッシュしないため、大量のデータを取得する場合に適しています。The DataReader is a good choice when you're retrieving large amounts of data because the data is not cached in memory.

DataReader を使用する例を次に示します。ここで、reader は有効な DataReader を、command は有効な Command オブジェクトを表します。The following example illustrates using a DataReader, where reader represents a valid DataReader and command represents a valid Command object.

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

クエリ結果から行を取得するには、DataReader.Read メソッドを使用します。Use the DataReader.Read method to obtain a row from the query results. 返された行の各列にアクセスするには、その列の名前または序数を DataReader に渡します。You can access each column of the returned row by passing the name or ordinal number of the column to the DataReader. ただし、DataReader では、最適のパフォーマンスが得られるように、ネイティブのデータ型を使用して列の値にアクセスできる一連のメソッド (GetDateTimeGetDoubleGetGuidGetInt32 など) が提供されています。However, for best performance, the DataReader provides a series of methods that allow you to access column values in their native data types (GetDateTime, GetDouble, GetGuid, GetInt32, and so on). データ プロバイダー固有の DataReader に対する型指定されたアクセサー メソッドの一覧については、OleDbDataReader および SqlDataReader を参照してください。For a list of typed accessor methods for data provider-specific DataReaders, see OleDbDataReader and SqlDataReader. 基になるデータ型がわかっているときは、型指定されたアクセサー メソッドを使用すると、列の値を取得するときに必要な型変換の量が少なくなります。Using the typed accessor methods when you know the underlying data type reduces the amount of type conversion required when retrieving the column value.

次に、DataReader オブジェクトを反復処理して各行から 2 つの列を返す例を示します。The following example iterates through a DataReader object and returns two columns from each row.

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

        SqlDataReader reader = command.ExecuteReader();

        if (reader.HasRows)
        {
            while (reader.Read())
            {
                Console.WriteLine("{0}\t{1}", reader.GetInt32(0),
                    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 の終了Closing the DataReader

DataReader オブジェクトを使い終えたら、Close メソッドを必ず呼び出します。Always call the Close method when you have finished using the DataReader object.

Command に出力パラメーターまたは戻り値が含まれている場合、DataReader が閉じられるまで、それらの値を使用することはできません。If your Command contains output parameters or return values, those values are not available until the DataReader is closed.

DataReader が開かれている間、Connection はその DataReader によって排他的に使用されています。While a DataReader is open, the Connection is in use exclusively by that DataReader. 元の DataReader が閉じられるまでは、別の DataReader の作成など、どのようなコマンドもその Connection に対して実行できません。You cannot execute any commands for the Connection, including creating another DataReader, until the original DataReader is closed.

注意

クラスの Finalize メソッド内では、ConnectionDataReader、またはその他のマネージド オブジェクトに対して、Close または Dispose を呼び出さないでください。Do not call Close or Dispose on a Connection, a DataReader, or any other managed object in the Finalize method of your class. 終了処理では、クラスに直接所有されているアンマネージ リソースだけを解放してください。In a finalizer, only release unmanaged resources that your class owns directly. クラスがアンマネージド リソースを所有していない場合は、クラス定義に Finalize メソッドを含めないでください。If your class does not own any unmanaged resources, do not include a Finalize method in your class definition. 詳しくは、「ガベージ コレクション」をご覧ください。For more information, see Garbage Collection.

NextResult による複数の結果セットの取得Retrieving multiple result sets using NextResult

DataReader から複数の結果セットが返される場合は、NextResult メソッドを呼び出して、結果セットを順番に反復処理します。If the DataReader returns multiple result sets, call the NextResult method to iterate through the result sets sequentially. SqlDataReader メソッドを使用して、2 つの SELECT ステートメントの結果を処理する ExecuteReader の例を次に示します。The following example shows the SqlDataReader processing the results of two SELECT statements using the ExecuteReader method.

static void RetrieveMultipleResults(SqlConnection connection)
{
    using (connection)
    {
        SqlCommand command = new SqlCommand(
          "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{0}\t{1}", reader.GetName(0),
                reader.GetName(1));

            while (reader.Read())
            {
                Console.WriteLine("\t{0}\t{1}", reader.GetInt32(0),
                    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 からのスキーマ情報の取得Getting schema information from the DataReader

DataReader が開かれている間に GetSchemaTable メソッドを使用して、現在の結果セットについてのスキーマ情報を取得できます。While a DataReader is open, you can retrieve schema information about the current result set using the GetSchemaTable method. GetSchemaTable は、現在の結果セットのスキーマ情報を含む行と列が設定されている DataTable オブジェクトを返します。GetSchemaTable returns a DataTable object populated with rows and columns that contain the schema information for the current result set. DataTable には結果セットの列ごとに 1 行が設定されます。The DataTable contains one row for each column of the result set. スキーマ テーブルの各列は、結果セットの行で返される列の 1 つのプロパティにマップされます。ColumnName はそのプロパティの名前であり、列の値はプロパティの値です。Each column of the schema table maps to a property of the columns returned in the rows of the result set, where the ColumnName is the name of the property and the value of the column is the value of the property. DataReader のスキーマ情報を出力する例を次に示します。The following example writes out the schema information for DataReader.

static void GetSchemaInfo(SqlConnection connection)
{
    using (connection)
    {
        SqlCommand command = new SqlCommand(
          "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 のチャプターの使用Working with OLE DB chapters

階層構造の行セット、つまりチャプター (OLE DB では DBTYPE_HCHAPTER 型、ADO では adChapter 型) は、OleDbDataReader を使用して取得できます。Hierarchical rowsets, or chapters (OLE DB type DBTYPE_HCHAPTER, ADO type adChapter), can be retrieved using the OleDbDataReader. チャプターを含むクエリが DataReader として返されるとき、チャプターはその DataReader の列として返され、DataReader オブジェクトとして公開されます。When a query that includes a chapter is returned as a DataReader, the chapter is returned as a column in that DataReader and is exposed as a DataReader object.

ADO.NET の DataSet を使用することで、テーブル間の親子のリレーションシップを使用して階層構造の行セットを表すこともできます。The ADO.NET DataSet can also be used to represent hierarchical rowsets by using parent-child relationships between tables. 詳しくは、「DataSet、DataTable、および DataView」をご覧ください。For more information, see DataSets, DataTables, and DataViews.

MSDataShape プロバイダーを使用して、顧客リストの顧客別オーダーのチャプター列を生成するコード サンプルを次に示します。The following code example uses the MSDataShape Provider to generate a chapter column of orders for each customer in a list of customers.

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 による結果の取得Returning results with Oracle REF CURSORs

.NET Framework Data Provider for Oracle は、クエリ結果を返すために、Oracle REF CURSOR の使用をサポートしています。The .NET Framework Data Provider for Oracle supports the use of Oracle REF CURSORs to return a query result. Oracle REF CURSOR は OracleDataReader として返されます。An Oracle REF CURSOR is returned as an OracleDataReader.

ExecuteReader メソッドを使用して、Oracle の REF CURSOR を表す OracleDataReader オブジェクトを取得できます。You can retrieve an OracleDataReader object that represents an Oracle REF CURSOR by using the ExecuteReader method. DataSet を設定するために使用される OracleDataAdapter に対する SelectCommand として 1 つまたは複数の Oracle の REF CURSOR を返す OracleCommand を指定することもできます。You can also specify an OracleCommand that returns one or more Oracle REF CURSORs as the SelectCommand for an OracleDataAdapter used to fill a DataSet.

Oracle データ ソースから返された REF CURSOR にアクセスするには、クエリ用の OracleCommand を作成し、OracleCommandParameters コレクションに、REF CURSOR を参照する出力パラメーターを追加します。To access a REF CURSOR returned from an Oracle data source, create an OracleCommand for your query and add an output parameter that references the REF CURSOR to the Parameters collection of your OracleCommand. パラメーターの名前は、クエリの REF CURSOR パラメーターの名前と一致させる必要があります。The name of the parameter must match the name of the REF CURSOR parameter in your query. パラメーターの型を OracleType.Cursor に設定します。Set the type of the parameter to OracleType.Cursor. OracleCommandOracleCommand.ExecuteReader() メソッドでは、REF CURSOR に対する OracleDataReader が返されます。The OracleCommand.ExecuteReader() method of your OracleCommand returns an OracleDataReader for the REF CURSOR.

OracleCommand で複数の REF CURSOR が返される場合は、複数の出力パラメーターを追加します。If your OracleCommand returns multiple REF CURSORS, add multiple output parameters. OracleCommand.ExecuteReader() メソッドを呼び出すことにより、異なる REF CURSOR にアクセスできます。You can access the different REF CURSORs by calling the OracleCommand.ExecuteReader() method. ExecuteReader() を呼び出すと、最初の REF CURSOR を参照している OracleDataReader が返されます。The call to ExecuteReader() returns an OracleDataReader referencing the first REF CURSOR. 次に OracleDataReader.NextResult() メソッドを呼び出すと、後続の REF CURSOR にアクセスできます。You can then call the OracleDataReader.NextResult() method to access subsequent REF CURSORs. OracleCommand.Parameters コレクションのパラメーターが REF CURSOR 出力パラメーターの名前と一致していても、OracleDataReader は、Parameters コレクションに追加された順に出力パラメーターにアクセスします。Although the parameters in your OracleCommand.Parameters collection match the REF CURSOR output parameters by name, the OracleDataReader accesses them in the order in which they were added to the Parameters collection.

たとえば、次のような Oracle パッケージとパッケージ本体があるとします。For example, consider the following Oracle package and package body.

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 つのパラメーターを OracleCommand.Parameters コレクションに追加することで、上の Oracle パッケージから REF CURSOR を返します。The following code creates an OracleCommand that returns the REF CURSORs from the previous Oracle package by adding two parameters of type OracleType.Cursor to the OracleCommand.Parameters collection.

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;  

OracleDataReaderRead() メソッドと NextResult() メソッドを使用して、上のコマンドの結果を返すコードを次に示します。The following code returns the results of the previous command using the Read() and NextResult() methods of the OracleDataReader. REF CURSOR パラメーターは順番に返されます。The REF CURSOR parameters are returned in order.

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 に設定する例を次に示します。The following example uses the previous command to populate a DataSet with the results of the Oracle package.

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 のデータ型に変換することをお勧めします。To avoid an OverflowException, we recommend that you also handle any conversion from the Oracle NUMBER type to a valid .NET Framework type before storing the value in a DataRow. FillError イベントを使用して、OverflowException が発生したかどうかを確認できます。You can use the FillError event to determine if an OverflowException has occurred. FillError イベントについて詳しくは、「DataAdapter のイベント処理」をご覧ください。For more information on the FillError event, see Handling DataAdapter Events.

関連項目See also