Condividi tramite


Recupero di dati mediante un DataReader (ADO.NET)

Per recuperare dati mediante un DataReader, è necessario creare un'istanza dell'oggetto Command, quindi creare un DataReader chiamando Command.ExecuteReader per recuperare righe da un'origine dati. Nell'esempio seguente è illustrato l'utilizzo di un DataReader in cui reader rappresenta un DataReader valido e command rappresenta un oggetto Command valido.

reader = command.ExecuteReader();

Il metodo Read dell'oggetto DataReader viene utilizzato per ottenere una riga dai risultati della query. È possibile accedere a ogni colonna della riga restituita passando il nome o il riferimento ordinale della colonna al DataReader. Per migliorare le prestazioni, tuttavia, DataReader fornisce una serie di metodi che consentono di accedere ai valori delle colonne nei tipi di dati nativi, quali GetDateTime, GetDouble, GetGuid, GetInt32 e così via. Per un elenco dei metodi delle funzioni di accesso tipizzate per DataReader specifici del provider di dati, vedere OleDbDataReader e SqlDataReader. L'utilizzo di metodi di funzioni di accesso tipizzate, quando si conosce il tipo di dati sottostante, riduce il numero di conversioni dei tipi necessari al momento del recupero del valore della colonna.

NotaNota

Nella versione di .NET Framework per Windows Server 2003 è inclusa una proprietà aggiuntiva per DataReader, HasRows, con cui è possibile determinare se DataReader ha restituito risultati prima di leggerli.

Nell'esempio di codice seguente viene scorso un oggetto DataReader e vengono restituite due colonne da ogni riga.

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 fornisce un flusso di dati non archiviati nel buffer che consente alla logica procedurale di elaborare sequenzialmente i risultati provenienti da un'origine dati. L'utilizzo di DataReader è consigliabile quando si recuperano grandi quantità di dati in quanto i dati non sono memorizzati nella cache.

Chiusura dell'oggetto DataReader

È necessario chiamare sempre il metodo Close una volta terminato l'utilizzo dell'oggetto DataReader.

I parametri di output o i valori restituiti presenti nell'oggetto Command non saranno disponibili fino a quando l'oggetto DataReader non viene chiuso.

Notare che quando è aperto un oggetto DataReader, l'oggetto Connection viene utilizzato esclusivamente da quell'oggetto DataReader. Non sarà possibile eseguire alcun comando per l'oggetto Connection, né creare un altro DataReader fino a quando il DataReader originale non viene chiuso.

NotaNota

Non chiamare Close o Dispose su un oggetto Connection, un oggetto DataReader o su qualsiasi altro oggetto gestito nel metodo Finalize della classe.Nei finalizzatori rilasciare solo le risorse non gestite che la classe controlla direttamente.Se nella classe non sono presenti risorse non gestite, non includere un metodo Finalize nella definizione della classe.Per ulteriori informazioni, vedere Garbage Collection.

Recupero di più set di risultati tramite NextResult

Se vengono restituiti più set di risultati, l'oggetto DataReader fornisce il metodo NextResult per scorrere in modo sequenziale i set di risultati. Nell'esempio seguente viene illustrata l'elaborazione dei risultati di due dichiarazioni SELECT da parte del tipo SqlDataReader utilizzando il metodo 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();
        }
    }
}

Recupero di informazioni sullo schema dall'oggetto DataReader

Mentre un oggetto DataReader è aperto, è possibile recuperare le informazioni sullo schema relative al set di risultati corrente utilizzando il metodo GetSchemaTable. Il metodo GetSchemaTable restituisce un oggetto DataTable compilato con righe e colonne contenenti le informazioni sullo schema del set di risultati corrente. L'oggetto DataTable contiene una riga per ogni colonna del set di risultati. Ogni colonna della riga nella tabella dello schema è associata a una proprietà della colonna restituita nel set di risultati, in cui ColumnName è il nome della proprietà e il valore della colonna è il valore della proprietà. Nell'esempio di codice seguente vengono rilasciate le informazioni sullo schema per l'oggetto 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]));
            }
        }
    }
}

Utilizzo dei capitoli OLE DB

I rowset gerarchici, o capitoli (tipo OLE DB DBTYPE_HCHAPTER, tipo ADO adChapter), possono essere recuperati utilizzando OleDbDataReader. Quando una query che include un capitolo viene restituita come un DataReader, il capitolo viene restituito come colonna del DataReader e viene esposto come un oggetto DataReader.

È possibile inoltre utilizzare il DataSet di ADO.NET per rappresentare rowset gerarchici utilizzando relazioni padre-figlio tra le tabelle. Per ulteriori informazioni, vedere DataSet, DataTable e DataView (ADO.NET).

Nell'esempio di codice seguente viene utilizzato il provider MSDataShape per generare una colonna del capitolo contenente gli ordini per ogni cliente presente 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")

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

Restituzione di risultati con i REF CURSOR Oracle

Con il provider di dati .NET Framework per Oracle è possibile utilizzare i REF CURSOR Oracle per la restituzione del risultato di una query. I REF CURSOR Oracle vengono restituiti come OracleDataReader.

È possibile recuperare un oggetto OracleDataReader che rappresenta un REF CURSOR Oracle utilizzando il metodo ExecuteReader ed è possibile specificare un OracleCommand che restituisca uno o più REF CURSOR Oracle come SelectCommand per un OracleDataAdapter utilizzato per compilare un DataSet.

Per accedere a un REF CURSOR restituito da un'origine dati Oracle, creare un OracleCommand per la query e aggiungere un parametro di output che fa riferimento al REF CURSOR alla raccolta Parameters di OracleCommand. È necessario che il nome del parametro corrisponda al nome del parametro REF CURSOR della query. Impostare il tipo di parametro su OracleType.Cursor. Il metodo ExecuteReader di OracleCommand restituirà un OracleDataReader per il REF CURSOR.

Se OracleCommand restituisce più REF CURSOR, aggiungere più parametri di output. Per accedere ai diversi REF CURSOR, chiamare il metodo OracleCommand.ExecuteReader. La chiamata a ExecuteReader restituirà un OracleDataReader che fa riferimento al primo REF CURSOR. Sarà quindi possibile chiamare il metodo OracleDataReader.NextResult per accedere ai REF CURSOR successivi. Sebbene la corrispondenza tra i parametri della raccolta OracleCommand.Parameters e i parametri di output di REF CURSOR avvenga per nome, OracleDataReader accederà ai parametri nell'ordine in cui questi sono stati aggiunti alla raccolta Parameters.

Si considerino ad esempio il package e il corpo package Oracle seguenti.

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; 

Con il codice seguente viene creato un oggetto OracleCommand che restituisce i REF CURSOR dal package Oracle precedente tramite l'aggiunta di due parametri di tipo OracleType.Cursor alla raccolta 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 il risultato del comando precedente tramite i metodi Read 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 utilizzato il comando precedente per compilare un DataSet con i risultati del package Oracle.

NotaNota

Per evitare il verificarsi di OverflowException, è consigliabile gestire le conversioni dei valori di tipo NUMBER Oracle in un tipo .NET Framework valido prima di archiviare i valori in un DataRow.Per determinare se si è verificata una OverflowException, è possibile utilizzare l'evento FillError.Per ulteriori informazioni sull'evento FillError, vedere Gestione degli eventi di 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);

Vedere anche

Altre risorse

Working with DataReaders

DataAdapter e DataReader (ADO.NET)

Comandi e parametri (ADO.NET)

Recupero di informazioni sullo schema di database (ADO.NET)