Hinweis
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, sich anzumelden oder das Verzeichnis zu wechseln.
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, das Verzeichnis zu wechseln.
Der SqlDataReader liest eine nur vorwärts durchlaufbare Ergebnissequenz aus einer SQL-Datenbank. Es lädt das vollständige Ergebnis nicht in ein DataSet, daher eignet es sich für die Verarbeitung von Zeilen, sobald sie eintreffen.
Bei den Beispielen in diesem Artikel wird davon ausgegangen, dass eine offene SqlConnection mit dem Namen connection auf die AdventureWorks-Beispieldatenbank abzielt.
Die C#-Beispiele erfordern using Microsoft.Data.SqlClient;. Beispiele, die SqlDbType oder CommandBehavior verwenden, erfordern ebenfalls using System.Data;.
Zeilen lesen
Der grundlegende Leser-Workflow ist:
- Führe einen Befehl mit
ExecuteReaderoderExecuteReaderAsyncaus. - Spaltenordinalzahlen für das aktuelle Ergebnis ermitteln.
- Ruf
Readeinmal pro Zeile an. - Überprüfe mit
IsDBNullSpalten, die Nullwerte zulassen, bevor du einen typisierten Getter aufrufst. - Geben Sie den Reader frei, bevor Sie die Verbindung wiederverwenden oder die Ausgabeparameter auslesen.
Dieses Beispiel zwischenspeichert Spaltenindizes, verwendet typisierte Zugriffsmethoden und prüft die Color nullable Spalte:
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)"}");
}
Das Aufrufen von GetString für einen NULL-Wert löst eine SqlNullValueException aus, überprüfen Sie also zuerst IsDBNull.
HasRows berichtet, ob das aktuelle Ergebnis Zeilen enthält, aber du kannst Read in der Regel direkt aufrufen. Für ein leeres Ergebnis gibt der erste Read Aufruf :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()}");
Für große Werte führen Sie mit CommandBehavior.SequentialAccess aus und benutzen GetStream, GetTextReader oder GetXmlReader. Weitere Informationen finden Sie unter SqlClient-Streamingunterstützung.
Schließen von DataReader
Entsorgen Sie den Reader sofort, sobald die Verarbeitung abgeschlossen ist. Eine await using- oder using-Anweisung schließt sie, selbst wenn die Zeilenverarbeitung eine Ausnahme auslöst.
Ausgabeparameter, Ein-/Ausgabeparameter und Rückgabewerte für gespeicherte Prozeduren sind erst endgültig, wenn der Leser geschlossen wird:
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}");
Ohne Multiple Active Result Sets (MARS) hält ein offener Reader seine Verbindung beschäftigt, und ein anderer Befehl kann auf dieser Verbindung nicht ausgeführt werden. Mit aktiviertem MARS können separate Befehle auf einer Verbindung ausstehende Ergebnisse haben, aber ihre Operationen sind trotzdem nicht threadsicher. Weitere Informationen finden Sie unter Multiple Active Result Sets.
Wenn der Befehl CommandBehavior.CloseConnection übergab, wird beim Schließen des Lesers auch die Verbindung geschlossen. Andernfalls bleibt der Code, der die Verbindung geöffnet hat, für ihre Freigabe verantwortlich.
Anzahl betroffener Zeilen lesen
RecordsAffected meldet die durch INSERT, UPDATE und DELETE-Anweisungen im Befehl geänderten Zeilen. Bitte lesen, nachdem der Leser geschlossen wurde. Dieses Beispiel macht sein Update rückgängig:
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();
Für einen SELECT-only Befehl RecordsAffected gilt -1.
SET NOCOUNT ON unterdrückt die Zählungen, wodurch auch der Wert bei -1 bleibt.
Mehrere Ergebnismengen mit NextResult abrufen
Ein Befehl oder gespeicherte Prozedur kann mehrere Ergebnisse liefern. Verarbeiten Sie das aktuelle Ergebnis vollständig und rufen Sie dann NextResultAsync oder NextResult auf:
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());
Spaltenanzahl, Namen, Ordinalzahlen und Typen können sich für jedes Ergebnis ändern. Berechnen Sie zwischengespeicherte Ordinalzahlen neu, nachdem NextResulttrue zurückgegeben hat.
Es kann jeweils nur eine asynchrone Operation auf einem Reader ausstehen. Warten Sie auf ReadAsync, NextResultAsync oder eine asynchrone Feldoperation, bevor Sie eine weitere Operation auf demselben Leser starten.
Abrufen von Schemainformationen aus dem DataReader-Objekt
Rufen Sie GetColumnSchema auf, um eine streng typisierte Beschreibung der aktuellen Spalten des Ergebnisses zu erhalten. Rufen Sie GetSchemaTable auf, wenn bestehender Code das Schema in einem DataTable benötigt:
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 fordert Spaltenmetadaten ohne Zeilen an. Die Schema-Informationen beschreiben die aktuelle Ergebnismenge. Fordern Sie es erneut an, nachdem Sie zum nächsten Ergebnis übergegangen sind. Je nach Abfrage und Serverberechtigungen könnten einige Metadaten der Basistabelle nicht verfügbar sein.