Abrufen von Daten mit einem 'DataReader' (ADO.NET)

Aktualisiert: November 2007

Wenn Sie Daten mit einem DataReader abrufen möchten, müssen Sie zunächst eine Instanz des Command-Objekts und anschließend einen DataReader erstellen. Rufen Sie hierzu Command.ExecuteReader auf, um Zeilen aus einer Datenquelle abzurufen. Im folgenden Beispiel wird die Verwendung eines DataReader gezeigt, wobei reader für einen gültigen DataReader und command für ein gültiges Command-Objekt steht.

reader = command.ExecuteReader();

Zum Abrufen einer Zeile aus den Abfrageergebnissen verwenden Sie die Read-Methode des DataReader-Objekts. Sie können auf jede Spalte der zurückgegebenen Zeile zugreifen, indem Sie dem DataReader den Namen oder den Ordinalzahlverweis der Spalte übergeben. Die beste Leistung erzielen Sie jedoch, wenn Sie die vom DataReader-Objekt bereitgestellten Methoden verwenden, mit denen Sie auf Spaltenwerte in ihren systemeigenen Datentypen zugreifen können (GetDateTime, GetDouble, GetGuid, GetInt32 usw.). Eine Liste mit typisierten Accessormethoden für anbieterspezifische DataReaders finden Sie unter OleDbDataReader und SqlDataReader. Mit den typisierten Accessormethoden wird der Aufwand für Typumwandlungen beim Abrufen eines Spaltenwerts reduziert, vorausgesetzt, der zugrunde liegende Datentyp ist bekannt.

Hinweis:

In der .NET Framework-Version für Windows Server 2003 verfügt DataReader über die zusätzliche HasRows-Eigenschaft, mit der vor dem Lesen ermittelt werden kann, ob der DataReader Ergebnisse zurückgegeben hat.

Im folgenden Codebeispiel wird ein DataReader-Objekt durchlaufen, und es werden von jeder Zeile zwei Spalten zurückgegeben.

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

Das DataReader-Objekt stellt einen nicht gepufferten Datenstream bereit, mit dem Prozeduren eine effektive, sequenzielle Verarbeitung der Ergebnisse aus einer Datenquelle ermöglicht wird. Ein DataReader ist zu empfehlen, wenn große Datenmengen abgerufen werden, da die Daten nicht zwischengespeichert werden.

Schließen des "DataReader"

Wenn ein DataReader-Objekt nicht mehr benötigt wird, sollte immer die Close-Methode aufgerufen werden.

Wenn ein Command Ausgabeparameter oder Rückgabewerte enthält, sind diese erst nach dem Schließen des DataReader verfügbar.

Beachten Sie, dass die Connection ausschließlich vom DataReader verwendet wird, solange der DataReader geöffnet ist. Sie können erst dann Befehle für die Connection ausführen, z. B. einen anderen DataReader erstellen, nachdem der erste DataReader geschlossen wurde.

Hinweis:

Rufen Sie in der Finalize-Methode einer Klasse für Connection-Objekte, DataReader-Objekte oder andere verwaltete Objekte nie Close oder Dispose auf. Geben Sie in einer Finalize-Methode nur nicht verwaltete Ressourcen frei, die der Klasse direkt gehören. Wenn die Klasse keine nicht verwalteten Ressourcen besitzt, definieren Sie in der Klasse keine Finalize-Methode. Weitere Informationen finden Sie unter Garbage Collection.

Abrufen mehrerer Resultsets mit "NextResult"

Wenn mehrere Resultsets zurückgegeben werden, können diese mit der NextResult-Methode von DataReader der Reihe nach durchlaufen werden. Im folgenden Beispiel werden die Ergebnisse von zwei SELECT-Anweisungen mit der ExecuteReader-Methode von SqlDataReader verarbeitet.

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

Abrufen von Schemainformationen aus dem "DataReader"

So lange ein DataReader geöffnet ist, können mit der GetSchemaTable-Methode Schemainformationen über das aktuelle Resultset abgerufen werden. GetSchemaTable gibt ein DataTable-Objekt zurück, das mit Zeilen und Spalten gefüllt ist, die die Schemainformationen für das aktuelle Resultset enthalten. Die DataTable enthält eine Zeile für jede Spalte des Resultset. Jede Spalte der Schematabellenzeile ist einer Eigenschaft der im Resultset zurückgegebenen Spalte zugeordnet, wobei ColumnName der Name der Eigenschaft und der Spaltenwert der Wert der Eigenschaft ist. Im folgenden Codebeispiel werden die Schemainformationen für DataReader geschrieben.

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

Arbeiten mit OLE DB-Kapiteln

Hierarchische Rowsets oder Kapitel (OLE DB-Typ DBTYPE_HCHAPTER, ADO-Typ adChapter) können mit dem OleDbDataReader abgerufen werden. Wenn eine Abfrage mit einem Kapitel als DataReader zurückgegeben wird, wird das Kapitel als Spalte in diesem DataReader zurückgegeben und als DataReader-Objekt verfügbar gemacht.

Mit dem ADO.NET-DataSet können auch hierarchische Rowsets dargestellt werden, die über- und untergeordnete Tabellen verwenden. Weitere Informationen finden Sie unter 'DataSets', 'DataTables' und 'DataViews' (ADO.NET).

Im folgenden Codebeispiel wird mit dem MSDataShape-Anbieter eine Kapitelspalte mit Bestellungen für jeden Kunden in einer Kundenliste generiert.

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

Zurückgeben von Ergebnissen mit Oracle-REF CURSORn

Der .NET Framework-Datenanbieter für Oracle unterstützt die Verwendung von Oracle-REF CURSORs zur Rückgabe eines Abfrageergebnisses. Ein Oracle-REF CURSOR wird als OracleDataReader zurückgegeben.

Sie können ein OracleDataReader-Objekt, das einen Oracle-REF CURSOR darstellt, mit der ExecuteReader-Methode abrufen. Außerdem können Sie für einen OracleDataAdapter, der zum Auffüllen eines DataSet verwendet wird, ein OracleCommand angeben, das einen oder mehrere Oracle-REF CURSORs als SelectCommand zurückgibt.

Erstellen Sie zum Zugreifen auf einen von einer Oracle-Datenquelle zurückgegebenen REF CURSOR einen OracleCommand für die Abfrage, und fügen Sie der Parameters-Auflistung des OracleCommand einen Ausgabeparameter hinzu, der auf den REF CURSOR verweist. Der Name des Parameters muss mit dem Namen des REF CURSOR-Parameters in der Abfrage übereinstimmen. Legen Sie den Typ des Parameters auf OracleType.Cursor fest. Die ExecuteReader-Methode des OracleCommand gibt einen OracleDataReader für den REF CURSOR zurück.

Wenn der OracleCommand mehrere REF CURSORs zurückgibt, fügen Sie mehrere Ausgabeparameter hinzu. Durch Aufrufen der OracleCommand.ExecuteReader-Methode können Sie auf die verschiedenen REF CURSORs zugreifen. Durch Aufrufen von ExecuteReader wird ein OracleDataReader zurückgegeben, der auf den ersten REF CURSOR verweist. Sie können dann mit der OracleDataReader.NextResult-Methode auf die nachfolgenden REF CURSORs zugreifen. Obwohl die Parameter der OracleCommand.Parameters-Auflistung dem Namen nach den REF CURSOR-Ausgabeparametern entsprechen, greift der OracleDataReader auf diese in der Reihenfolge zu, in der sie der Parameters-Auflistung hinzugefügt wurden.

Betrachten Sie z. B. das folgende Oracle-Paket und den Paketkörper.

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; 

Im folgenden Codebeispiel wird ein OracleCommand erstellt, der die REF CURSORs aus dem oben stehenden Oracle-Paket zurückgibt. Hierzu werden der Parameters-Auflistung zwei Parameter vom Typ OracleType.Cursor hinzugefügt.

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;

Im folgenden Codebeispiel werden die Ergebnisse des Befehls aus dem vorherigen Beispiel mit der Read-Methode und der NextResult-Methode des OracleDataReader zurückgegeben. Die REF CURSOR-Parameter werden der Reihe nach zurückgegeben.

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

Im folgenden Beispiel wird der Befehl aus dem vorherigen Codebeispiel verwendet, um ein DataSet mit den Ergebnissen des Oracle-Pakets aufzufüllen.

Hinweis:

Zur Vermeidung einer OverflowException wird empfohlen, alle notwendigen Konvertierungen vom Oracle-Typ NUMBER in einen gültigen .NET Framework-Typ vor dem Speichern des Werts in einer DataRow auszuführen. Mit dem FillError-Ereignis kann festgestellt werden, ob eine OverflowException aufgetreten ist. Weitere Informationen zum FillError-Ereignis finden Sie unter Umgang mit 'DataAdapter'-Ereignissen (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);

Siehe auch

Weitere Ressourcen

'DataReaders' (ADO.NET)

'DataAdapters' und 'DataReaders' (ADO.NET)

Befehle und Parameter (ADO.NET)

Abrufen von Schemainformationen aus einer Datenbank (ADO.NET)