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.
SqlDataReader liest eine nur vorwärts durchlaufbare Ergebnissequenz aus einer SQL-Datenbank aus. Es lädt das vollständige Ergebnis nicht in ein DataSet, daher eignet es sich für die Verarbeitung von Zeilen, sobald sie eintreffen.
Die Beispiele in diesem Artikel gehen davon aus, dass ein offenes SqlConnection mit dem Namen connection auf die AdventureWorks-Beispieldatenbank verweist.
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 GetString eines Wertes NULL wirft SqlNullValueException, also prüfe IsDBNull zuerst.
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 using- oder await 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, bis der Reader 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 übergeben wurde, 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. Lies es, nachdem der Reader 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 erneut, nachdem NextResulttrue zurückgibt.
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 Reader 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.