Извлечение данных с помощью DataReader (ADO.NET)

Обновлен: November 2007

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

reader = command.ExecuteReader();

Метод Read объекта DataReader используется для получения строки из результатов запроса. Доступ к отдельным столбцам возвращенной строки осуществляется по имени или порядковому номеру столбца через объект DataReader. Однако для максимальной производительности объект DataReader предоставляет ряд методов, позволяющих обращаться к значениям столбцов в их собственных типах данных (GetDateTime, GetDouble, GetGuid, GetInt32 и т. д.). Список типизированных методов доступа в объектах DataReader для конкретных поставщиков данных см. в разделах OleDbDataReader и SqlDataReader. Использование типизированных методов доступа при условии, что известен базовый тип данных, сокращает объем преобразований типов, необходимых при извлечении значения столбца.

haa3afyz.alert_note(ru-ru,VS.90).gifПримечание.

В версии платформы .NET Framework для Windows Server 2003 имеется дополнительное свойство объекта DataReader, HasRows, которое позволяет определить, возвратил ли объект DataReader какие-либо результаты, перед тем как читать из него.

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

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

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

Закрытие DataReader

По окончании использования объекта DataReader всегда следует вызывать метод Close.

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

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

haa3afyz.alert_note(ru-ru,VS.90).gifПримечание.

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

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

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

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

Получение данных схемы от DataReader

Когда открыт объект DataReader, с помощью метода GetSchemaTable можно получить данные схемы о текущем результирующем наборе. Метод GetSchemaTable возвращает объект DataTable, заполненный строками и столбцами, которые содержат данные схемы для текущего результирующего набора. Объект DataTable содержит одну строку для каждого столбца результирующего набора. Каждый столбец строки таблицы схемы соответствует свойству столбца, возвращенного в результирующем наборе, где ColumnName — это имя свойства, а значение столбца — это значение свойства. В следующем примере кода на консоль выводятся данные схемы для объекта DataReader.

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

Работа с разделами OLE DB

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

Для представления иерархических наборов строк при помощи связей типа «родитель-потомок» между таблицами также можно использовать объект ADO.NET DataSet. Дополнительные сведения см. в разделе Объекты DataSet, DataTable и DataView (ADO.NET).

В следующем примере кода поставщик MSDataShape используется, чтобы сформировать столбец раздела заказов по каждому клиенту из списка клиентов.

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

Dim 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()

Dim custReader As OleDbDataReader = custCMD.ExecuteReader()
Dim orderReader As OleDbDataReader

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

  orderReader = 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()
Loop
' Make sure to always close readers and connections.
custReader.Close()
End Using
Using (OleDbConnection connection = new OleDbConnection(
  "Provider=MSDataShape;Data Provider=SQLOLEDB;" +
  "Data Source=localhost;Integrated Security=SSPI;Initial Catalog=northwind"));
{
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();

OleDbDataReader custReader = custCMD.ExecuteReader();
OleDbDataReader orderReader;

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

  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 для Oracle поддерживает использование параметров Oracle REF CURSOR для возвращения результата запроса. Параметр Oracle REF CURSOR возвращается в виде объекта OracleDataReader.

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

Чтобы получить доступ к параметру REF CURSOR, возвращенному из источника данных Oracle, создайте экземпляр OracleCommand для данного запроса и добавьте выходной параметр, устанавливающий ссылку между REF CURSOR и коллекцией Parameters данного экземпляра OracleCommand. Имя параметра должно соответствовать имени параметра REF CURSOR, используемого в запросе. В качестве типа параметра установите OracleType.Cursor. Метод ExecuteReader данного экземпляра OracleCommand возвратит объект OracleDataReader для параметра REF CURSOR.

Если экземпляр OracleCommand возвращает несколько параметров REF CURSOR, добавьте несколько выходных параметров. Доступ к разным параметрам REF CURSOR можно получать с помощью метода OracleCommand.ExecuteReader. Вызов метода ExecuteReader возвращает объект OracleDataReader, ссылающийся на первый параметр REF CURSOR. Затем можно вызвать метод 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, который возвращает параметры REF CURSOR из предыдущего пакета Oracle путем добавления двух параметров типа OracleType.Cursor в коллекцию 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.

haa3afyz.alert_note(ru-ru,VS.90).gifПримечание.

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

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

См. также

Другие ресурсы

Объекты DataReader (ADO.NET)

Объекты DataAdapter и DataReader (ADO.NET)

Команды и параметры (ADO.NET)

Получение сведений о схеме базы данных (ADO.NET)