Получение данных с помощью DataReaderRetrieve data using a DataReader

Для получения данных с помощью DataReader создайте экземпляр объекта Command, а затем создайте DataReader путем вызова Command.ExecuteReader для получения строк из источника данных.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 представляет допустимый объект команды.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 предоставляет ряд методов, которые дают возможность обращаться к значениям столбцов в собственных типах данных (GetDateTime, GetDouble, GetGuid, GetInt32, и так далее).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 и возврат двух столбцов из каждой строки.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

Закрытие DataReaderClosing the DataReader

Всегда вызывайте метод Close после завершения использования объекта DataReader.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 не закрыт, для объекта Connection невозможно выполнение команд, в том числе создание еще одного DataReader.You cannot execute any commands for the Connection, including creating another DataReader, until the original DataReader is closed.

Примечание

Не вызывайте Close или Dispose для объектов Connection, DataReader или любого другого управляемого объекта в методе Finalize класса.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.

Получение нескольких результирующих наборов с помощью Некстресулт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. В следующем примере показана обработка результатов двух инструкций SELECT в SqlDataReader с помощью метода 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

Получение сведений о схеме из DataReaderGetting 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 содержит по одной строке для каждого столбца результирующего набора.The DataTable contains one row for each column of the result set. Каждый столбец в таблице схемы соответствует свойству столбца, возвращаемого в строках результирующего набора, где 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 DBWorking with OLE DB chapters

Иерархические наборы строк или главы (OLE DB Type DBTYPE_HCHAPTER, ADO Type адчаптер) можно 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.

DataSet из ADO.NET также может использоваться для представления иерархических наборов строк с использованием отношений "родитель — потомок" между таблицами.The ADO.NET DataSet can also be used to represent hierarchical rowsets by using parent-child relationships between tables. Дополнительные сведения см. в разделе Наборы данных, таблицы данных и объекты 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();
        }
    }
}

Возврат результатов с использованием параметров REF CURSOR OracleReturning results with Oracle REF CURSORs

Поставщик данных .NET Framework для 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.

Вы можете получить объект OracleDataReader, представляющий Oracle REF CURSOR, используя метод ExecuteReader.You can retrieve an OracleDataReader object that represents an Oracle REF CURSOR by using the ExecuteReader method. Можно также указать OracleCommand, возвращающий один или несколько REF CURSOR Oracle, в качестве SelectCommand для OracleDataAdapter, используемого для заполнения DataSet.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.

Чтобы получить доступ к REF CURSOR, возвращенному из источника данных Oracle, создайте запрос OracleCommand и добавьте выходной параметр, который ссылается на REF CURSOR, в коллекцию Parameters вашего объекта OracleCommand.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. Метод OracleCommand.ExecuteReader() вашего объекта OracleCommand возвращает OracleDataReader для параметра REF CURSOR.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. Можно получить доступ к разным параметрам REF CURSOR, вызвав метод OracleCommand.ExecuteReader().You can access the different REF CURSORs by calling the OracleCommand.ExecuteReader() method. Вызов ExecuteReader() возвращает OracleDataReader, ссылающийся на первый REF CURSOR.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, которая возвращает параметры REF CURSOR из приведенного выше пакета Oracle путем добавления двух параметров типа OracleType.Cursor в коллекцию OracleCommand.Parameters.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;  

Следующий код возвращает результаты приведенной выше команды, используя методы Read() и NextResult() объекта OracleDataReader.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();  

В следующем примере приведенная выше команда используется для заполнения DataSet результатами пакета Oracle.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, рекомендуется также производить преобразование из типа Oracle NUMBER в допустимый тип .NET Framework перед сохранением значения в DataRow.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. Чтобы отследить возникновение OverflowException, можно использовать событие FillError.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