Recuperando dados usando um DataReaderRetrieving Data Using a DataReader

Recuperando dados usando um DataReader envolve a criação de uma instância do comando objeto e, em seguida, criando um DataReader chamando ExecuteReader para recuperar linhas de uma fonte de dados.Retrieving data using a DataReader involves creating an instance of the Command object and then creating a DataReader by calling Command.ExecuteReader to retrieve rows from a data source. O exemplo a seguir ilustra o uso uma DataReader onde reader representa um DataReader válido e command representa um objeto de comando válido.The following example illustrates using a DataReader where reader represents a valid DataReader and command represents a valid Command object.

reader = command.ExecuteReader();  

Você usa o leitura método o DataReader para obter uma linha dos resultados da consulta.You use the Read method of the DataReader object to obtain a row from the results of the query. Você pode acessar cada coluna da linha retornada, passando o nome ou a referência ordinal da coluna para o DataReader.You can access each column of the returned row by passing the name or ordinal reference of the column to the DataReader. No entanto, para melhor desempenho, o DataReader fornece uma série de métodos que permitem que você acesse os valores de coluna em seus tipos de dados nativos (GetDateTime, GetDouble, GetGuid, GetInt32, e assim por diante).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). Para obter uma lista de métodos de acessador tipado para dados específicos do provedor DataReaders, consulte OleDbDataReader e SqlDataReader.For a list of typed accessor methods for data provider-specific DataReaders, see OleDbDataReader and SqlDataReader. Usar os métodos de acessador tipados, supondo-se que o tipo de dados subjacente seja conhecido, reduz a quantidade de conversão de tipos necessária ao recuperar o valor da coluna.Using the typed accessor methods, assuming the underlying data type is known, reduces the amount of type conversion required when retrieving the column value.

Observação

A versão do Windows Server 2003 do .NET Framework inclui uma propriedade adicional para o DataReader, HasRows, que permite que você determine se o DataReaderretornou nenhum resultado antes da leitura dele.The Windows Server 2003 release of the .NET Framework includes an additional property for the DataReader, HasRows, which enables you to determine if the DataReader has returned any results before reading from it.

O exemplo de código a seguir itera por meio de um DataReader objeto e retorna duas colunas de cada linha.The following code 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

O DataReader fornece um fluxo sem buffer de dados que permite que a lógica de procedimento processar com eficácia sequencialmente os resultados de uma fonte de dados.The DataReader provides an unbuffered stream of data that allows procedural logic to efficiently process results from a data source sequentially. O DataReader é uma boa opção quando recuperar grandes quantidades de dados porque os dados não é armazenado em cache na memória.The DataReader is a good choice when retrieving large amounts of data because the data is not cached in memory.

Fechando o DataReaderClosing the DataReader

Você sempre deve chamar o fechar método quando você terminar de usar o DataReader objeto.You should always call the Close method when you have finished using the DataReader object.

Se seu comando contém saída parâmetros ou valores de retorno, eles não estarão disponíveis até que o DataReader está fechado.If your Command contains output parameters or return values, they will not be available until the DataReader is closed.

Observe que, embora uma DataReader é aberto, o Conexão está em uso exclusivamente pelo DataReader.Note that while a DataReader is open, the Connection is in use exclusively by that DataReader. Não é possível executar os comandos para o Conexão, incluindo a criação de outro DataReader, até que o original DataReader está fechado.You cannot execute any commands for the Connection, including creating another DataReader, until the original DataReader is closed.

Observação

Não chame fechar ou Dispose em uma Conexão, um DataReader, ou qualquer outro objeto gerenciado no Finalize método de sua classe.Do not call Close or Dispose on a Connection, a DataReader, or any other managed object in the Finalize method of your class. Em um finalizador, libere somente recursos não gerenciados que sua classe possui diretamente.In a finalizer, only release unmanaged resources that your class owns directly. Se sua classe não possui todos os recursos não gerenciados, não inclua um Finalize método em sua definição de classe.If your class does not own any unmanaged resources, do not include a Finalize method in your class definition. Para obter mais informações, consulte coleta de lixo.For more information, see Garbage Collection.

Recuperando vários conjuntos de resultados usando NextResultRetrieving Multiple Result Sets using NextResult

Se vários conjuntos de resultados são retornados, o DataReader fornece o NextResult define um método para iterar o resultados em ordem.If multiple result sets are returned, the DataReader provides the NextResult method to iterate through the result sets in order. O exemplo a seguir mostra SqlDataReader processando os resultados de duas instruções SELECT usando o método 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

Obtendo informações de esquema do DataReaderGetting Schema Information from the DataReader

Enquanto um DataReader é aberto, você pode recuperar informações de esquema sobre o resultado atual definido usando o GetSchemaTable método.While a DataReader is open, you can retrieve schema information about the current result set using the GetSchemaTable method. GetSchemaTable retorna um DataTable objeto preenchido com linhas e colunas que contêm as informações de esquema para o conjunto de resultados atual.GetSchemaTable returns a DataTable object populated with rows and columns that contain the schema information for the current result set. O DataTable contém uma linha para cada coluna do conjunto de resultados.The DataTable contains one row for each column of the result set. Cada coluna da linha da tabela de esquema é mapeado para uma propriedade da coluna retornada no conjunto de resultados, onde o ColumnName é o nome da propriedade e o valor da coluna é o valor da propriedade.Each column of the schema table row maps to a property of the column returned in the result set, where the ColumnName is the name of the property and the value of the column is the value of the property. O exemplo de código a seguir grava as informações de esquema DataReader.The following code 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

Trabalhando com capítulos OLE DBWorking with OLE DB Chapters

Conjuntos de linhas hierárquicos, ou capítulos (tipo de OLE DB DBTYPE_HCHAPTER, tipo ADO adChapter) podem ser recuperados usando o OleDbDataReader.Hierarchical rowsets, or chapters (OLE DB type DBTYPE_HCHAPTER, ADO type adChapter) can be retrieved using the OleDbDataReader. Quando uma consulta que inclui um capítulo é retornada como um DataReader, o capítulo é retornado como uma coluna em que DataReader e é exposto como um DataReader objeto.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.

O ADO.NET DataSet também pode ser usado para representar os conjuntos de linhas hierárquicos usando relações pai-filho entre tabelas.The ADO.NET DataSet can also be used to represent hierarchical rowsets using parent-child relationships between tables. Para obter mais informações, consulte DataSets, DataTables e DataViews.For more information, see DataSets, DataTables, and DataViews.

O exemplo de código a seguir usa o provedor de MSDataShape para gerar uma coluna de capítulo de pedidos para cada cliente em uma lista de clientes.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")  

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

Retornando resultados com REF CURSORs OracleReturning Results with Oracle REF CURSORs

O Provedor de Dados .NET Framework para Oracle oferece suporte ao uso de REF CURSORs Oracle para retornar um resultado de consulta.The .NET Framework Data Provider for Oracle supports the use of Oracle REF CURSORs to return a query result. Um REF CURSOR Oracle é retornado como um OracleDataReader.An Oracle REF CURSOR is returned as an OracleDataReader.

Você pode recuperar um OracleDataReader objeto que representa um Oracle REF CURSOR usando o ExecuteReader método e você também pode especificar um OracleCommand que retorna um ou mais REF CURSORs do Oracle como o SelectCommand para um OracleDataAdapter usado para preencher um DataSet.You can retrieve an OracleDataReader object, that represents an Oracle REF CURSOR using the ExecuteReader method, and 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.

Para acessar uma REF CURSOR retornado de uma fonte de dados Oracle, crie um OracleCommand para sua consulta e adicione um parâmetro de saída que faz referência a REF CURSOR para o parâmetros coleção de seu 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. O nome do parâmetro deve corresponder ao nome do parâmetro REF CURSOR em sua consulta.The name of the parameter must match the name of the REF CURSOR parameter in your query. Defina o tipo do parâmetro para OracleType.Set the type of the parameter to OracleType.Cursor. O ExecuteReader método de sua OracleCommand retornará um OracleDataReader para REF CURSOR.The ExecuteReader method of your OracleCommand will return an OracleDataReader for the REF CURSOR.

Se seu OracleCommand retorna vários CURSORES REF, adicionar vários parâmetros de saída.If your OracleCommand returns multiple REF CURSORS, add multiple output parameters. Você pode acessar os cursores de referência diferente chamando o OracleCommand.ExecuteReader método.You can access the different REF CURSORs by calling the OracleCommand.ExecuteReader method. A chamada para ExecuteReader retorna um OracleDataReader faz referência ao CURSOR REF primeiro.The call to ExecuteReader returns an OracleDataReader referencing the first REF CURSOR. Em seguida, você pode chamar o OracleDataReader.NextResult método para acessar os cursores de REF subsequentes.You can then call the OracleDataReader.NextResult method to access subsequent REF CURSORs. Embora os parâmetros em seu OracleCommand.Parameters parâmetros de saída de correspondência de coleção REF CURSOR por nome, o OracleDataReader acessa-los na ordem em que foram adicionados para o Parâmetros coleção.Although the parameters in your OracleCommand.Parameters collection match the REF CURSOR output parameters by name, the OracleDataReader accesses them in the order that they were added to the Parameters collection.

Por exemplo, considere o seguinte pacote Oracle e o corpo do pacote.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;   

O código a seguir cria um OracleCommand que retorna os cursores de referência de pacote Oracle anterior adicionando dois parâmetros de tipo OracleType para o parâmetros coleção.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 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;  

O código a seguir retorna os resultados do comando anterior usando o leitura e NextResult métodos do OracleDataReader.The following code returns the results of the previous command using the Read and NextResult methods of the OracleDataReader. Os parâmetros REF CURSOR são retornados em ordem.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();  

O exemplo a seguir usa o comando anterior para preencher um DataSet com os resultados do pacote Oracle.The following example uses the previous command to populate a DataSet with the results of the Oracle package.

Observação

Para evitar um OverflowException, é recomendável que você também pode manipular qualquer conversão do tipo de número de Oracle como um tipo válido do .NET Framework antes de armazenar o valor em uma 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. Você pode usar o FillError evento para determinar se um OverflowException ocorreu.You can use the FillError event to determine if an OverflowException has occurred. Para obter mais informações sobre o FillError evento, consulte manipulando eventos de DataAdapter.For more information on the FillError event, see Handling DataAdapter Events.

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

Consulte tambémSee Also

Trabalhando com DataReadersWorking with DataReaders
DataAdapters e DataReadersDataAdapters and DataReaders
Comandos e parâmetrosCommands and Parameters
Recuperando informações de esquema de banco de dadosRetrieving Database Schema Information
ADO.NET Managed Providers and DataSet Developer Center (Central de desenvolvedores do DataSet e de provedores gerenciados do ADO.NET)ADO.NET Managed Providers and DataSet Developer Center