Condividi tramite


Recupera dati usando un DataReader

Per recuperare i dati usando un DataReader, creare un'istanza dell'oggetto Command e quindi creare un Oggetto DataReader chiamando Command.ExecuteReader per recuperare righe da un'origine dati. DataReader fornisce un flusso di dati senza buffer che consente alla logica procedurale di elaborare in modo efficiente i risultati da un'origine dati in sequenza. DataReader è una scelta ottimale quando si recuperano grandi quantità di dati perché i dati non vengono memorizzati nella cache in memoria.

Nell'esempio seguente viene illustrato l'utilizzo di un oggetto DataReader, dove reader rappresenta un DataReader valido e command rappresenta un oggetto Command valido.

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

Utilizzare il metodo DataReader.Read per ottenere una riga dai risultati della query. È possibile accedere a ogni colonna della riga restituita passando il nome o il numero ordinale della colonna a DataReader. Tuttavia, per ottenere prestazioni ottimali, DataReader offre una serie di metodi che consentono di accedere ai valori delle colonne nei tipi di dati nativi (GetDateTime, GetDouble, GetGuid, GetInt32 e così via). Per un elenco dei metodi di accesso tipizzati per i DataReader specifici del provider di dati, vedere OleDbDataReader e SqlDataReader. L'uso dei metodi di accesso tipizzato quando si conosce il tipo di dati sottostante riduce la necessità di conversioni di tipo durante il recupero del valore della colonna.

L'esempio seguente scorre un oggetto DataReader e restituisce due colonne per ciascuna riga.

static void HasRows(SqlConnection connection)
{
    using (connection)
    {
        SqlCommand command = new(
          "SELECT CategoryID, CategoryName FROM Categories;",
          connection);
        connection.Open();

        SqlDataReader reader = command.ExecuteReader();

        if (reader.HasRows)
        {
            while (reader.Read())
            {
                Console.WriteLine($"{reader.GetInt32(0)}\t{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

Chiusura di DataReader

Chiamare sempre il metodo Close al termine dell'utilizzo dell'oggetto DataReader .

Se il comando contiene parametri di output o valori restituiti, tali valori non sono disponibili fino alla chiusura di DataReader .

Mentre un DataReader è aperto, la connessione è in uso esclusivamente da tale DataReader. Non è possibile eseguire comandi per la connessione, inclusa la creazione di un altro DataReader, fino alla chiusura del DataReader originale.

Annotazioni

Non chiamare Close o Dispose per una connessione, un DataReader o qualsiasi altro oggetto gestito nel metodo Finalize della classe. Nei finalizzatori, rilascia solo le risorse non gestite che appartengono direttamente alla tua classe. Se la classe non possiede risorse non gestite, non includere un metodo Finalize nella definizione della classe. Per altre informazioni, vedere Garbage Collection.

Recupero di più set di risultati tramite NextResult

Se DataReader restituisce più set di risultati, chiamare il metodo NextResult per scorrere i set di risultati in sequenza. Nell'esempio seguente viene illustrata l'elaborazione SqlDataReader dei risultati di due istruzioni SELECT usando il ExecuteReader metodo .

static void RetrieveMultipleResults(SqlConnection connection)
{
    using (connection)
    {
        SqlCommand command = new(
          "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{reader.GetName(0)}\t{reader.GetName(1)}");

            while (reader.Read())
            {
                Console.WriteLine($"\t{reader.GetInt32(0)}\t{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

Recupero di informazioni sullo schema da DataReader

Mentre un DataReader è aperto, è possibile recuperare informazioni sullo schema del set di risultati corrente usando il metodo GetSchemaTable. GetSchemaTable restituisce un DataTable oggetto popolato con righe e colonne contenenti le informazioni sullo schema per il set di risultati corrente. DataTable contiene una riga per ogni colonna del set di risultati. Ogni colonna della tabella dello schema viene mappata a una proprietà delle colonne restituite nelle righe del set di risultati, dove ColumnName è il nome della proprietà e il valore della colonna è il valore della proprietà . L'esempio seguente scrive le informazioni sullo schema per DataReader.

static void GetSchemaInfo(SqlConnection connection)
{
    using (connection)
    {
        SqlCommand command = new(
          "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

Lavorare con i capitoli di OLE DB

I set di righe gerarchici o i capitoli (tipo OLE DB DBTYPE_HCHAPTER, adChapter di tipo ADO), possono essere recuperati usando .OleDbDataReader Quando una query che include un capitolo viene restituita come DataReader, il capitolo viene restituito come colonna in tale DataReader ed è esposto come oggetto DataReader .

Il ADO.NET DataSet può essere usato anche per rappresentare set di righe gerarchici usando relazioni padre-figlio tra tabelle. Per altre informazioni, vedere DataSet, DataTables e DataViews.

Nell'esempio di codice seguente viene usato il provider MSDataShape per generare una colonna capitolo di ordini per ogni cliente in un elenco di clienti.

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

Restituzione di risultati con ORACLE REF CURSORs

Il provider di dati .NET Framework per Oracle supporta l'uso di ORACLE REF CURSOR per restituire un risultato della query. Un Oracle REF CURSOR viene restituito come un OracleDataReader.

È possibile recuperare un OracleDataReader oggetto che rappresenta un oracle REF CURSOR utilizzando il ExecuteReader metodo . È anche possibile specificare un OracleCommand che restituisce uno o più REF CURSOR Oracle come SelectCommand per un OracleDataAdapter usato per riempire un DataSet.

Per accedere a un CURSORE REF restituito da un'origine dati Oracle, crea un oggetto OracleCommand per la tua query e aggiungi un parametro di output che fa riferimento al CURSORE REF alla raccolta di Parameters del tuo OracleCommand. Il nome del parametro deve corrispondere al nome del parametro REF CURSOR nella query. Impostare il tipo del parametro su OracleType.Cursor. Il metodo OracleCommand.ExecuteReader() di OracleCommand restituisce un OracleDataReader per il REF CURSOR.

Se il tuo OracleCommand restituisce più CURSORI REF, aggiungi più parametri di output. È possibile accedere ai diversi CURSOR REF chiamando il OracleCommand.ExecuteReader() metodo . La chiamata a ExecuteReader() restituisce un OracleDataReader che fa riferimento al primo REF CURSOR. È quindi possibile chiamare il OracleDataReader.NextResult() metodo per accedere ai CURSOR REF successivi. Anche se i parametri nella raccolta OracleCommand.Parameters corrispondono ai parametri di output REF CURSOR in base al nome, il OracleDataReader accede a questi nell'ordine in cui sono stati aggiunti alla raccolta Parameters.

Ad esempio, considera il seguente pacchetto Oracle e il corpo del pacchetto.

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;

Il codice seguente crea un oggetto OracleCommand che restituisce i REF CURSOR dal pacchetto Oracle precedente aggiungendo due parametri di tipo OracleType.Cursor alla collezione 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;  

Il codice seguente restituisce i risultati del comando precedente usando i Read() metodi e NextResult() di OracleDataReader. I parametri REF CURSOR vengono restituiti in ordine.

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

Nell'esempio seguente viene usato il comando precedente per popolare un DataSet oggetto con i risultati del pacchetto 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);  

Annotazioni

Per evitare un'eccezione OverflowException, è consigliabile gestire anche qualsiasi conversione dal tipo di dati Oracle NUMBER a un tipo .NET Framework valido prima di memorizzare il valore in un oggetto DataRow. È possibile utilizzare l'evento FillError per determinare se si è verificata un'eccezione OverflowException . Per altre informazioni sull'evento FillError , vedere Gestione degli eventi DataAdapter.

Vedere anche