Recuperar dados usando um DataReader

Para recuperar dados usando um DataReader, crie uma instância do objeto Command e, em seguida, crie um DataReader chamando Command.ExecuteReader a fim de recuperar linhas de uma fonte de dados. O DataReader fornece um fluxo de dados não armazenado em buffer que permite que a lógica procedural processe resultados com eficiência por meio de uma fonte de dados em sequência. O DataReader é uma boa opção ao recuperar grandes quantidades de dados porque os dados não são armazenados em cache na memória.

O exemplo a seguir ilustra o uso de um DataReader, em que representa um DataReader válido e command representa um objeto Command válido.

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

Use o método DataReader.Read para obter uma linha dos resultados da consulta. É possível acessar cada coluna da linha retornada passando o nome ou o número ordinal da coluna para o DataReader. No entanto, para oferecer o melhor desempenho, o DataReader fornece uma série de métodos que permitem que você acesse valores de coluna nos tipos de dados nativos delas (GetDateTime, GetDouble, GetGuid, GetInt32 e assim por diante). Para ver uma lista de métodos de acessador digitados para DataReaders específicos do provedor de dados, consulte e SqlDataReader. Usar os métodos acessadores tipados quando você já conhece o tipo de dados subjacente, reduz a quantidade de conversão de tipos necessária ao recuperar o valor da coluna.

O exemplo a seguir faz a iteração por meio de um objeto DataReader e retorna duas colunas de cada linha.

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

Fechando o DataReader

Sempre chame o método Close quando terminar de usar o objeto DataReader.

Se o Command contiver parâmetros de saída ou valores de retorno, esses valores não serão disponibilizados até que o DataReader seja fechado.

Enquanto um DataReader estiver aberto, a Connection estará sendo usada exclusivamente por esse DataReader. Você não poderá executar nenhum comando usando a Connection, incluindo criar um outro DataReader, até o DataReader original esteja fechado.

Observação

Não chame Close nem Dispose em um Connection, um DataReader ou qualquer outro objeto gerenciado no método Finalize da classe. Em um finalizador, libere somente recursos não gerenciados que sua classe possui diretamente. Se a classe não tiver nenhum recurso não gerenciado, não inclua um método Finalize na definição de classe. Para obter mais informações, confira Coleta de lixo.

Recuperando vários conjuntos de resultados usando NextResult

Se o DataReader retornar vários conjuntos de resultados, chame o método NextResult para percorrer os conjuntos de resultados em sequência. O exemplo a seguir mostra SqlDataReader processando os resultados de duas instruções SELECT usando o método 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

Obter informações de esquema do DataReader

Enquanto o DataReader estiver aberto, você poderá recuperar informações de esquema sobre o conjunto de resultados atual usando o método GetSchemaTable. GetSchemaTable retorna um objeto preenchido com linhas e colunas que contêm as informações de esquema para o conjunto de resultados atual. O DataTable contém uma linha para cada coluna do conjunto de resultados. Cada coluna da tabela do esquema é mapeada para uma propriedade da coluna retornada nas linhas do conjunto de resultados, onde ColumnName é o nome da propriedade e o valor da coluna é o valor da propriedade. O exemplo a seguir gravará as informações de esquema para o 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 OLE DB capítulos

Conjuntos de linhas hierárquicos ou capítulos (OLE DB tipo DBTYPE_HCHAPTER, tipo ADO adChapter), podem ser recuperados usando o . Quando uma consulta que inclui um capítulo é retornada como um DataReader, o capítulo é retornado como uma coluna nesse DataReader e é exposto como um objeto DataReader .

O ADO.NET DataSet também pode ser usado para representar conjuntos de linhas hierárquicos usando relações pai-filho entre tabelas. Para obter mais informações, consulte DataSets, DataTables e 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.

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

Retornando resultados com REF CURSORs oracle

O Provedor de Dados .NET Framework para Oracle oferece suporte ao uso de REF CURSORs Oracle para retornar um resultado de consulta. Um REF CURSOR Oracle é retornado como um OracleDataReader.

Você pode recuperar um OracleDataReader objeto que representa um ORACLE REF CURSOR usando o ExecuteReader método . Você também pode especificar um OracleCommand que retorna um ou mais REF CURSORs oracle como OracleCommand para OracleDataAdapter um usado para preencher um DataSet.

Para acessar um REF CURSOR retornado de uma fonte de dados Oracle, OracleCommand crie um para sua consulta e adicione um parâmetro de saída que faz referência ao REF CURSOR Parameters à coleção de OracleCommandseu . O nome do parâmetro deve corresponder ao nome do parâmetro REF CURSOR em sua consulta. De definir o tipo do parâmetro como OracleType.Cursor. O OracleCommand.ExecuteReader() método de retorna OracleCommand um OracleDataReader para o REF CURSOR.

Se o retornar OracleCommand vários REF CURSORS, adicione vários parâmetros de saída. Você pode acessar os diferentes REF CURSORs chamando o OracleCommand.ExecuteReader() método . A chamada para ExecuteReader() retorna uma OracleDataReader referência ao primeiro REF CURSOR. Em seguida, você pode chamar o OracleDataReader.NextResult() método para acessar REF CURSORs subsequentes. Embora os parâmetros em sua OracleCommand.Parameters coleção sejam de acordo com os parâmetros de saída REF CURSOR por nome, OracleDataReader o os acessa na ordem em que foram adicionados à Parameters coleção.

Por exemplo, considere o seguinte pacote Oracle e o corpo do pacote.

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 OracleCommand um que retorna os REF CURSORs do pacote Oracle anterior adicionando dois parâmetros do tipo OracleType.Cursor à OracleCommand.Parameters coleção.

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 os Read() métodos NextResult() e do OracleDataReader. Os parâmetros REF CURSOR são retornados em ordem.

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 popular um DataSet com os resultados do pacote 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);  

Observação

Para evitar um OverflowException, recomendamos que você também manipular qualquer conversão do tipo Oracle NUMBER em um tipo .NET Framework válido antes de armazenar o valor em um . Você pode usar o FillError evento para determinar se FillError ocorreu. Para obter mais informações sobre o FillError evento, consulte FillError.

Confira também