Nota
L'accesso a questa pagina richiede l'autorizzazione. È possibile provare ad accedere o modificare le directory.
L'accesso a questa pagina richiede l'autorizzazione. È possibile provare a modificare le directory.
SqlDataReader legge una sequenza di risultati solo in avanti da un database SQL. Non carica il risultato completo in un DataSet, quindi è adatto per l'elaborazione delle righe man mano che arrivano.
Gli esempi in questo articolo presuppongono che una connessione connection aperta denominata SqlConnection sia destinata al database di esempio AdventureWorks.
Gli esempi di C# richiedono using Microsoft.Data.SqlClient;. Esempi che usano SqlDbType o CommandBehavior richiedono using System.Data;anche .
Leggi righe
Il flusso di lavoro base del lettore è:
- Esegui un comando con
ExecuteReaderoExecuteReaderAsync. - Determina gli indici di colonna per il risultato corrente.
- Chiama
Readuna volta per ogni riga. - Controlla le colonne nullable con
IsDBNullprima di chiamare un getter tipizzato. - Elimina il reader prima di riutilizzare la connessione o leggere i parametri di uscita.
Questo esempio memorizza in cache gli ordinali delle colonne, utilizza getter tipizzati e controlla la colonna nullabile Color :
using var command = new SqlCommand("""
SELECT ProductID, Name, Color
FROM Production.Product
WHERE ProductSubcategoryID = @subcategoryId
ORDER BY ProductID;
""", connection);
command.Parameters.Add("@subcategoryId", SqlDbType.Int).Value = 2;
using SqlDataReader reader = command.ExecuteReader();
int idOrdinal = reader.GetOrdinal("ProductID");
int nameOrdinal = reader.GetOrdinal("Name");
int colorOrdinal = reader.GetOrdinal("Color");
while (reader.Read())
{
int id = reader.GetInt32(idOrdinal);
string name = reader.GetString(nameOrdinal);
string? color = reader.IsDBNull(colorOrdinal)
? null
: reader.GetString(colorOrdinal);
Console.WriteLine($"{id} | {name} | {color ?? "(no color)"}");
}
Chiamare GetString su un valore NULL genera SqlNullValueException, quindi controlla prima IsDBNull
HasRows Segnala se il risultato attuale contiene righe, ma di solito puoi chiamare Read direttamente. Per un risultato vuoto, la prima Read chiamata restituisce false:
using var command = new SqlCommand("""
SELECT ProductID
FROM Production.Product
WHERE ProductID = @productId;
""", connection);
command.Parameters.Add("@productId", SqlDbType.Int).Value = -1;
using SqlDataReader reader = command.ExecuteReader();
Console.WriteLine($"HasRows: {reader.HasRows}");
Console.WriteLine($"First Read: {reader.Read()}");
Per valori grandi, esegui con CommandBehavior.SequentialAccess e usa GetStream, GetTextReader, o GetXmlReader. Per maggiori informazioni, consulta il supporto allo streaming di SqlClient.
Chiudi il DataReader
Rilasciare il reader non appena la lavorazione è terminata. Un'istruzione using o await using istruzione la chiude anche quando l'elaborazione delle righe genera un'eccezione.
I parametri di output, i parametri di input/output e i valori di ritorno delle stored procedure non sono definitivi fino alla chiusura del lettore:
using var command = new SqlCommand("""
SELECT TOP (5) ProductID, Name
FROM Production.Product
ORDER BY ProductID;
SET @count = @@ROWCOUNT;
""", connection);
SqlParameter count = command.Parameters.Add("@count", SqlDbType.Int);
count.Direction = ParameterDirection.Output;
using (SqlDataReader reader = command.ExecuteReader())
{
while (reader.Read())
{
Console.WriteLine(reader.GetString(1));
}
}
Console.WriteLine($"Rows returned: {count.Value}");
Senza Multiple Active Result Set (MARS), un lettore aperto mantiene occupata la sua connessione e un altro comando non può essere eseguito su quella connessione. Con MARS abilitato, comandi separati possono avere risultati in attesa su una connessione, ma le loro operazioni non sono comunque thread-safe. Per maggiori informazioni, vedi Multiple Active Result Sets.
Se viene passato il comando CommandBehavior.CloseConnection, anche la chiusura del reader chiude la connessione. Altrimenti, il codice che ha aperto la connessione rimane responsabile della chiusura.
Leggere i conteggi delle righe interessate
RecordsAffected riporta le righe modificate dalle istruzioni INSERT, UPDATE e DELETE nel comando. Leggilo dopo che Reader si è chiuso. Questo esempio ripristina il proprio aggiornamento:
using SqlTransaction transaction = connection.BeginTransaction();
using var command = new SqlCommand("""
UPDATE Production.Product
SET ModifiedDate = ModifiedDate
WHERE ProductID IN (706, 707);
SELECT ProductID, Name
FROM Production.Product
WHERE ProductID IN (706, 707)
ORDER BY ProductID;
""", connection, transaction);
SqlDataReader reader = command.ExecuteReader();
using (reader)
{
while (reader.Read())
{
Console.WriteLine($"{reader.GetInt32(0)} | {reader.GetString(1)}");
}
}
Console.WriteLine($"RecordsAffected: {reader.RecordsAffected}");
transaction.Rollback();
Per un comando con solo SELECT, RecordsAffected è -1.
SET NOCOUNT ON sopprime i conteggi, lasciando anche il valore a -1.
Recupera più set di risultati usando NextResult
Un comando o una procedura memorizzata può restituire più risultati. Elaborare completamente il risultato corrente, e poi chiamare NextResult o NextResultAsync
using var command = new SqlCommand("""
SELECT TOP (3) ProductID, Name
FROM Production.Product
ORDER BY ProductID;
SELECT COUNT(*) AS ProductCount
FROM Production.Product;
""", connection);
using SqlDataReader reader = command.ExecuteReader();
int result = 1;
do
{
Console.WriteLine($"Result {result++}: {reader.FieldCount} column(s)");
while (reader.Read())
{
var values = new object[reader.FieldCount];
reader.GetValues(values);
Console.WriteLine(string.Join(" | ", values));
}
}
while (reader.NextResult());
Il numero di colonne, nomi, ordinali e tipi possono cambiare per ogni risultato. Ricalcola gli ordinali nella cache dopo che NextResult restituisce true.
Può essere in attesa di un lettore solo un'operazione asincrona alla volta. Attendere ReadAsync, NextResultAsync, o un'operazione asincrona su un campo prima di iniziare un'altra operazione sullo stesso lettore.
Ottenere informazioni sullo schema da DataReader
Chiama GetColumnSchema per una descrizione fortemente tipizzata delle colonne del risultato corrente. Invoca GetSchemaTable quando il codice esistente ha bisogno dello schema in un DataTable:
using var command = new SqlCommand("""
SELECT ProductID, Name, Color
FROM Production.Product;
""", connection);
using SqlDataReader reader = command.ExecuteReader(
CommandBehavior.SchemaOnly);
foreach (System.Data.Common.DbColumn column in reader.GetColumnSchema())
{
Console.WriteLine(
$"{column.ColumnOrdinal}: {column.ColumnName} " +
$"({column.DataTypeName}), nullable={column.AllowDBNull}");
}
CommandBehavior.SchemaOnly richiede metadati delle colonne senza restituire righe. Le informazioni dello schema descrivono il set di risultati corrente. Richiedelo di nuovo dopo essere passato al risultato successivo. A seconda della query e dei permessi del server, alcuni metadati della tabella base potrebbero non essere disponibili.