Извлечение данных с помощью объекта DataReader

Чтобы получить данные с помощью DataReader, создайте экземпляр объекта Command , а затем создайте объект DataReader , вызвав Command.Exeкутереадер для получения строк из источника данных. DataReader предоставляет небуферизованный поток данных, позволяющий процедурной логике эффективно обрабатывать результаты из источника данных. DataReader является хорошим выбором при извлечении больших объемов данных, поскольку данные не кэшируются в памяти.

В следующем примере показано использование DataReader, где reader представляет допустимый DataReader и command представляет допустимый объект команды.

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

Используйте метод DataReader. Read для получения строки из результатов запроса. Доступ к каждому столбцу возвращаемой строки можно получить, передав имя или порядковый номер столбца в DataReader. Однако для лучшей производительности DataReader предоставляет ряд методов, позволяющих получить доступ к значениям столбцов в собственных типах данных (типыDateTime, double , DataColumn, Int32и т. д.). Список типизированных методов доступа для DataReader, относящихся к поставщику данных, см OleDbDataReader . в разделе и SqlDataReader . Использование типизированных методов доступа, если известно, что базовый тип данных сокращает объем преобразования типа, необходимый при извлечении значения столбца.

В следующем примере выполняется итерация объекта DataReader и возвращаются два столбца из каждой строки.

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

Всегда вызывайте метод Close после завершения использования объекта DataReader .

Если команда содержит выходные параметры или возвращаемые значения, эти значения недоступны до закрытия DataReader .

Когда DataReader открыт, соединение используется исключительно этим объектом DataReader. Нельзя выполнять команды для соединения, включая создание другого DataReader, пока не будет закрыт исходный DataReader .

Примечание

Не вызывайте Close или Dispose для соединения, DataReaderили любого другого управляемого объекта в методе Finalize вашего класса. В методе завершения следует только освобождать неуправляемые ресурсы, которыми ваш класс непосредственно владеет. Если ваш класс не владеет какими-либо неуправляемыми ресурсами, не включайте метод Finalize в определение класса. Дополнительные сведения см. в разделе сборка мусора.

Получение нескольких результирующих наборов с помощью Некстресулт

Если DataReader возвращает несколько результирующих наборов, вызовите метод некстресулт для последовательного прохода по результирующим наборам. В следующем примере показан объект SqlDataReader, обрабатывающий результаты двух инструкций SELECT с помощью метода ExecuteReader.

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

Когда DataReader открыт, можно получить сведения о схеме текущего результирующего набора с помощью метода GetSchemaTable . GetSchemaTable возвращает DataTable объект, заполненный строками и столбцами, содержащими сведения о схеме для текущего результирующего набора. Объект DataTable содержит по одной строке для каждого столбца результирующего набора. Каждый столбец таблицы схемы сопоставляется со свойством столбцов, возвращаемых строками результирующего набора, где ColumnName является именем свойства, а значение столбца — значением свойства. В следующем примере записывается информация о схеме для 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 главами

Иерархические наборы строк или главы (тип OLE DB DBTYPE_HCHAPTER, тип ADO адчаптер) можно получить с помощью OleDbDataReader . Если запрос, включающий главу, возвращается в виде объекта DataReader, то эта глава возвращается в виде столбца в объекте DataReader и предоставляется как объект DataReader .

Набор данных ADO.NET также можно использовать для представления иерархических наборов строк с помощью связей типа «родители-потомки» между таблицами. Дополнительные сведения см. в разделе наборы данных, DataTables и DataSets.

В следующем примере кода поставщик 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

Поставщик данных .NET Framework для Oracle поддерживает использование параметров Oracle REF CURSOR для возвращения результата запроса. Параметр Oracle REF CURSOR возвращается в виде объекта OracleDataReader.

OracleDataReaderОбъект, представляющий курсор Oracle ref, можно получить с помощью ExecuteReader метода. Можно также указать OracleCommand , возвращающий один или несколько курсоров Oracle ref в качестве SelectCommand для, OracleDataAdapter используемого для заполнения DataSet .

Чтобы получить доступ к КУРСОРу REF, возвращенному из источника данных Oracle, создайте OracleCommand для запроса и добавьте выходной параметр, который ссылается на ссылочный курсор, в Parameters коллекцию OracleCommand . Имя параметра должно соответствовать имени параметра REF CURSOR, используемого в запросе. Задайте для параметра Тип значение OracleType.Cursor . OracleCommand.ExecuteReader()Метод OracleCommand ВОЗВРАЩАЕТ OracleDataReader для курсора ref.

Если функция OracleCommand возвращает несколько курсоров ref, добавьте несколько выходных параметров. Чтобы получить доступ к разным КУРСОРам REF, вызовите OracleCommand.ExecuteReader() метод. Вызов метода ExecuteReader() возвращает ссылку на OracleDataReader первый курсор ref. Затем можно вызвать OracleDataReader.NextResult() метод для доступа к последовательным курсорам ref. Хотя параметры в 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 , который возвращает ссылки на ref из предыдущего пакета Oracle, добавляя два параметра типа OracleType.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();  

В следующем примере используется предыдущая команда для заполнения DataSet с результатами пакета Oracle.

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);  

Примечание

Чтобы избежать переполнения, рекомендуется также выполнять преобразование из типа номера Oracle в допустимый тип .NET Framework перед сохранением значения в DataRow . Можно использовать событие, FillError чтобы определить, произошло ли исключение OverflowException . Дополнительные сведения о FillError событии см. в разделе Обработка событий DataAdapter.

См. также раздел