Recuperación de datos mediante DataReaderRetrieve data using a DataReader

Para recuperar datos mediante un DataReader, cree una instancia del objeto de comando y, a continuación, cree un DataReader mediante una llamada a Command. ExecuteReader para recuperar las filas de un origen de datos.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 proporciona un flujo de datos no almacenado en búfer que permite que la lógica de procedimientos procese eficazmente los resultados de un origen de datos de forma secuencial.The DataReader provides an unbuffered stream of data that allows procedural logic to efficiently process results from a data source sequentially. DataReader es una buena elección cuando se recuperan grandes cantidades de datos porque los datos no se almacenan en la memoria caché.The DataReader is a good choice when you're retrieving large amounts of data because the data is not cached in memory.

En el ejemplo siguiente se muestra el uso de DataReader, donde reader representa un DataReader válido y command representa un 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();  
reader = command.ExecuteReader()

Use el método DataReader. Read para obtener una fila de los resultados de la consulta.Use the DataReader.Read method to obtain a row from the query results. Puede tener acceso a cada columna de la fila devuelta pasando el nombre o el número ordinal de la columna al DataReader.You can access each column of the returned row by passing the name or ordinal number of the column to the DataReader. Sin embargo, para obtener el mejor rendimiento, DataReader proporciona una serie de métodos que le permiten tener acceso a los valores de columna en sus tipos de datos nativos (GetDateTime, getDouble, GetGuid, GetInt32, etc.).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 obtener una lista de métodos de descriptor de acceso con tipo para los DataReaderespecíficos OleDbDataReader del SqlDataReaderproveedor de datos, vea y.For a list of typed accessor methods for data provider-specific DataReaders, see OleDbDataReader and SqlDataReader. El uso de los métodos de descriptor de acceso con tipo cuando se conoce el tipo de datos subyacente reduce la cantidad de conversión de tipos necesaria al recuperar el valor de la columna.Using the typed accessor methods when you know the underlying data type reduces the amount of type conversion required when retrieving the column value.

En el ejemplo siguiente se recorre en iteración un objeto DataReader y se devuelven dos columnas de cada fila.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

Cerrar el DataReaderClosing the DataReader

Llame siempre al método Close cuando haya terminado de usar el objeto DataReader .Always call the Close method when you have finished using the DataReader object.

Si el comando contiene parámetros de salida o valores devueltos, esos valores no estarán disponibles hasta que se cierre DataReader .If your Command contains output parameters or return values, those values are not available until the DataReader is closed.

Mientras un DataReader está abierto, la conexión está en uso exclusivamente por parte de DataReader.While a DataReader is open, the Connection is in use exclusively by that DataReader. No se puede ejecutar ningún comando para la conexión, incluida la creación de otro DataReader, hasta que se cierre el DataReader original.You cannot execute any commands for the Connection, including creating another DataReader, until the original DataReader is closed.

Nota

No llame a Close o Dispose en una conexión, DataReadero cualquier otro objeto administrado en el método Finalize de la clase.Do not call Close or Dispose on a Connection, a DataReader, or any other managed object in the Finalize method of your class. En un finalizador, libere solo los recursos no administrados que pertenezcan directamente a su clase.In a finalizer, only release unmanaged resources that your class owns directly. Si la clase no posee recursos no administrados, no incluya un método Finalize en la definición de clase.If your class does not own any unmanaged resources, do not include a Finalize method in your class definition. Para obtener más información, consulte recolección de elementos no utilizados.For more information, see Garbage Collection.

Recuperar varios conjuntos de resultados mediante NextResultRetrieving multiple result sets using NextResult

Si DataReader devuelve varios conjuntos de resultados, llame al método NextResult para recorrer en iteración los conjuntos de resultados secuencialmente.If the DataReader returns multiple result sets, call the NextResult method to iterate through the result sets sequentially. En el siguiente ejemplo se muestra el SqlDataReader mientras procesa los resultados de las dos instrucciones SELECT mediante el 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

Obtención de información de esquema de DataReaderGetting schema information from the DataReader

Mientras un DataReader está abierto, puede recuperar información de esquema sobre el conjunto de resultados actual mediante el método GetSchemaTable .While a DataReader is open, you can retrieve schema information about the current result set using the GetSchemaTable method. GetSchemaTable devuelve un DataTable objeto rellenado con filas y columnas que contienen la información de esquema para el conjunto de resultados actual.GetSchemaTable returns a DataTable object populated with rows and columns that contain the schema information for the current result set. El objeto DataTable contiene una fila por cada columna del conjunto de resultados.The DataTable contains one row for each column of the result set. Cada columna de la tabla de esquema se asigna a una propiedad de las columnas devueltas en las filas del conjunto de resultados, donde columnName es el nombre de la propiedad y el valor de la columna es el valor de la propiedad.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. En el ejemplo siguiente se escribe la información de esquema de 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

Trabajar con capítulos de OLE DBWorking with OLE DB chapters

Los conjuntosOleDbDataReaderde filas jerárquicos, o capítulos (OLE DB Type DBTYPE_HCHAPTER, adChapter Type de ADO), se pueden recuperar mediante.Hierarchical rowsets, or chapters (OLE DB type DBTYPE_HCHAPTER, ADO type adChapter), can be retrieved using the OleDbDataReader. Cuando una consulta que incluye un capítulo se devuelve como un DataReader, el capítulo se devuelve como una columna en ese DataReader y se expone como un objeto 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.

El conjunto de ADO.net también se puede usar para representar conjuntos de filas jerárquicos mediante el uso de relaciones de elementos primarios y secundarios entre las tablas.The ADO.NET DataSet can also be used to represent hierarchical rowsets by using parent-child relationships between tables. Para obtener más información, vea conjuntos de datos , tablas de datos y vistasde datos.For more information, see DataSets, DataTables, and DataViews.

En el ejemplo de código siguiente se utiliza el proveedor MSDataShape para generar un capítulo con la columna de pedidos realizados por cada uno de los clientes de una lista.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();
        }
    }
}

Devolver resultados con CURSOres REF CURSOR de OracleReturning results with Oracle REF CURSORs

El proveedor de datos .NET Framework para Oracle admite el uso de cursores REF CURSOR de Oracle para devolver los resultados de una consulta.The .NET Framework Data Provider for Oracle supports the use of Oracle REF CURSORs to return a query result. Un REF CURSOR de Oracle se devuelve en forma de objeto OracleDataReader.An Oracle REF CURSOR is returned as an OracleDataReader.

Puede recuperar un OracleDataReader objeto que representa un cursor Ref cursor de Oracle mediante el ExecuteReader método.You can retrieve an OracleDataReader object that represents an Oracle REF CURSOR by using the ExecuteReader method. También OracleCommand puede especificar un que devuelve uno o varios cursores REF cursor de Oracle como SelectCommand para un OracleDataAdapter utilizado para rellenar un. DataSetYou 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 tener acceso a un Ref cursor devuelto desde un origen de datos OracleCommand de Oracle, cree un para la consulta y agregue un parámetro de salida que Parameters haga referencia al OracleCommandcursor Ref a la colección de.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. El nombre del parámetro debe coincidir con el nombre del parámetro REF CURSOR de la consulta.The name of the parameter must match the name of the REF CURSOR parameter in your query. Establezca el tipo del parámetro en OracleType.Cursor.Set the type of the parameter to OracleType.Cursor. El OracleCommand.ExecuteReader() método OracleDataReader de devuelve un para el cursor Ref. OracleCommandThe OracleCommand.ExecuteReader() method of your OracleCommand returns an OracleDataReader for the REF CURSOR.

OracleCommand Si devuelve varios cursores REF cursor, agregue varios parámetros de salida.If your OracleCommand returns multiple REF CURSORS, add multiple output parameters. Puede tener acceso a los diferentes cursores REF cursor llamando OracleCommand.ExecuteReader() al método.You can access the different REF CURSORs by calling the OracleCommand.ExecuteReader() method. La llamada a ExecuteReader() devuelve un OracleDataReader que hace referencia al primer cursor Ref.The call to ExecuteReader() returns an OracleDataReader referencing the first REF CURSOR. Después, puede llamar al OracleDataReader.NextResult() método para tener acceso a los siguientes cursores REF cursor.You can then call the OracleDataReader.NextResult() method to access subsequent REF CURSORs. Aunque los parámetros de la OracleCommand.Parameters colección coinciden con los parámetros de salida Ref cursor por OracleDataReader nombre, el obtiene acceso a ellos en el orden en que se Parameters agregaron a la colección.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.

Por ejemplo, considere el siguiente paquete de Oracle y, concretamente, el cuerpo del paquete.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;   

En el código siguiente se OracleCommand crea un que devuelve los cursores REF cursor del paquete anterior de Oracle agregando dos OracleType.Cursor parámetros de OracleCommand.Parameters tipo a la colección.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;  

El código siguiente devuelve los resultados del comando anterior mediante los Read() métodos y NextResult() de. OracleDataReaderThe following code returns the results of the previous command using the Read() and NextResult() methods of the OracleDataReader. Los parámetros REF CURSOR se devuelven en orden.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();  

En el ejemplo siguiente se usa el comando anterior para DataSet rellenar un con los resultados del paquete de 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);  

Nota

Para evitar una excepción OverflowException, se recomienda que también se controle cualquier conversión del tipo Number de Oracle a un tipo de .NET Framework válido antes de almacenar DataRowel valor en.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. Puede utilizar el FillError evento para determinar si se ha producido una excepción OverflowException .You can use the FillError event to determine if an OverflowException has occurred. Para obtener más información sobre FillError el evento, vea controlar eventos DataAdapter.For more information on the FillError event, see Handling DataAdapter Events.

Vea tambiénSee also