Freigeben über


Abrufen von Daten mithilfe eines DataReader

Wenn Sie Daten mit einem DataReader-Objekt abrufen möchten, müssen Sie zunächst eine Instanz des Command-Objekts und anschließend ein DataReader-Objekt erstellen, indem Sie Command.ExecuteReader aufrufen, um Zeilen aus einer Datenquelle abzurufen. Das DataReader-Objekt stellt einen ungepufferten Datenstrom bereit, mit dem prozeduraler Logik eine effektive sequenzielle Verarbeitung der Ergebnisse aus einer Datenquelle ermöglicht wird. Das DataReader-Objekt ist gut für das Abrufen großer Datenmengen geeignet, da die Daten nicht im Arbeitsspeicher zwischengespeichert werden.

Im folgenden Beispiel wird die Verwendung eines DataReader-Objekts gezeigt, wobei reader für ein gültiges DataReader-Objekt und command für ein gültiges Command-Objekt steht.

reader = command.ExecuteReader();  
reader = command.ExecuteReader()

Verwenden Sie die DataReader.Read-Methode, um eine Zeile aus den Abfrageergebnissen abzurufen. Sie können auf jede Spalte der zurückgegebenen Zeile zugreifen, indem Sie dem DataReader-Objekt den Namen oder die Ordinalzahl 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 nativen Datentypen zugreifen können (z. B. GetDateTime, GetDouble, GetGuid oder GetInt32). Eine Liste der typierten Accessormethoden für datenanbieterspezifische DataReaders finden Sie unter OleDbDataReader und SqlDataReader. Mit den typisierten Accessormethoden wird die Menge der beim Abrufen des Spaltenwerts erforderlichen Typkonvertierungen reduziert, wenn der zugrunde liegende Datentyp bekannt ist.

Im folgenden Beispiel wird ein DataReader-Objekt durchlaufen, wobei von jeder Zeile zwei Spalten zurückgegeben werden.

static void HasRows(SqlConnection connection)
{
    using (connection)
    {
        SqlCommand command = new(
          "SELECT CategoryID, CategoryName FROM Categories;",
          connection);
        connection.Open();

        SqlDataReader reader = command.ExecuteReader();

        if (reader.HasRows)
        {
            while (reader.Read())
            {
                Console.WriteLine($"{reader.GetInt32(0)}\t{reader.GetString(1)}");
            }
        }
        else
        {
            Console.WriteLine("No rows found.");
        }
        reader.Close();
    }
}
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

Schließen des DataReader

Rufen Sie immer die Close-Methode auf, wenn Sie die Verwendung des DataReader-Objekts abgeschlossen haben.

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

Solange ein DataReader-Objekt geöffnet ist, wird das Connection-Objekt ausschließlich von diesem DataReader-Objekt verwendet. Sie können erst dann Befehle für das Connection-Objekt ausführen, z. B. um ein anderes DataReader-Objekt zu erstellen, wenn das ursprüngliche DataReader-Objekt geschlossen wurde.

Hinweis

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

Abrufen mehrerer Resultsets mithilfe von NextResult

Wenn das DataReader-Objekt mehrere Resultsets zurückgibt, rufen Sie die NextResult-Methode auf, um die Resultsets nacheinander zu durchlaufen. Im folgenden Beispiel werden die Ergebnisse von zwei SELECT-Anweisungen mit der SqlDataReader-Methode von ExecuteReader verarbeitet.

static void RetrieveMultipleResults(SqlConnection connection)
{
    using (connection)
    {
        SqlCommand command = new(
          "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{reader.GetName(0)}\t{reader.GetName(1)}");

            while (reader.Read())
            {
                Console.WriteLine($"\t{reader.GetInt32(0)}\t{reader.GetString(1)}");
            }
            reader.NextResult();
        }
    }
}
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

Abrufen von Schemainformationen vom DataReader

Solange ein DataReader-Objekt geöffnet ist, können Sie mit der GetSchemaTable-Methode Schemainformationen zum aktuellen Resultset abrufen. GetSchemaTable gibt ein DataTable-Objekt zurück, das mit Zeilen und Spalten gefüllt ist, die die Schemainformationen für das aktuelle Resultset enthalten. Das DataTable-Objekt enthält eine Zeile für jede Spalte des Resultsets. Jede Spalte der Schematabelle ist einer Eigenschaft der zurückgegebenen Spalten in den Zeilen des Resultsets zugeordnet, wobei ColumnName der Name der Eigenschaft und der Spaltenwert der Wert der Eigenschaft ist. Im folgenden Beispiel werden die Schemainformationen für DataReader abgerufen.

static void GetSchemaInfo(SqlConnection connection)
{
    using (connection)
    {
        SqlCommand command = new(
          "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]));
            }
        }
    }
}
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

Arbeiten mit OLE DB-Kapiteln

Hierarchische Rowsets oder Kapitel (OLE DB-Typ DBTYPE_HCHAPTER, ADO-Typ adChapter) können mithilfe des OleDbDataReader abgerufen werden. Wenn eine Abfrage, die ein Kapitel enthält, als DataReader zurückgegeben wird, wird das Kapitel als Spalte in diesem DataReader zurückgegeben und als DataReader-Objekt verfügbar gemacht.

Das ADO.NET DataSet kann auch verwendet werden, um hierarchische Rowsets durch Eltern-Kind-Beziehungen zwischen Tabellen darzustellen. Weitere Informationen finden Sie unter DataSets, DataTables und DataViews.

Im folgenden Codebeispiel wird der MSDataShape-Anbieter verwendet, um eine Kapitelspalte mit Bestellungen für jeden Kunden in einer Kundenliste zu generieren.

Using connection As OleDbConnection = New OleDbConnection(
    "Provider=MSDataShape;Data Provider=SQLOLEDB;" &
    "Data Source=localhost;Integrated Security=SSPI;Initial Catalog=northwind")

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

        Using custReader As OleDbDataReader = custCMD.ExecuteReader()

            Do While custReader.Read()
                Console.WriteLine("Orders for " & custReader.GetString(1))
                ' custReader.GetString(1) = CompanyName  

                Using orderReader As OleDbDataReader = 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()
                End Using
            Loop
            ' Make sure to always close readers and connections.  
            custReader.Close()
        End Using
    End Using
End Using
using (OleDbConnection connection = new OleDbConnection(
    "Provider=MSDataShape;Data Provider=SQLOLEDB;" +
    "Data Source=localhost;Integrated Security=SSPI;Initial Catalog=northwind"))
{
    using (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();

        using (OleDbDataReader custReader = custCMD.ExecuteReader())
        {

            while (custReader.Read())
            {
                Console.WriteLine("Orders for " + custReader.GetString(1));
                // custReader.GetString(1) = CompanyName  

                using (OleDbDataReader 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 CURSORs

Der .NET Framework-Datenanbieter für Oracle unterstützt die Verwendung von Oracle REF CURSORs, um ein Abfrageergebnis zurückzugeben. Ein Oracle REF CURSOR wird als ein OracleDataReader zurückgegeben.

Sie können ein OracleDataReader Objekt abrufen, das einen Oracle REF CURSOR darstellt, indem Sie die ExecuteReader Methode verwenden. Außerdem können Sie für ein OracleCommand-Objekt, das zum Auffüllen von verwendet wird, ein OracleDataAdapter-Objekt angeben, das den REF CURSOR-Datentyp von Oracle als DataSet zurückgibt.

Um auf einen von einer Oracle-Datenquelle zurückgegebenen REF CURSOR zuzugreifen, erstellen Sie ein OracleCommand für Ihre Abfrage und fügen Sie einen Ausgabeparameter hinzu, der auf den REF CURSOR in der Parameters-Sammlung Ihres OracleCommand verweist. Der Name des Parameters muss mit dem Namen des REF CURSOR-Parameters in Ihrer Abfrage übereinstimmen. Legen Sie den Typ des Parameters auf OracleType.Cursor. Die OracleCommand.ExecuteReader()-Methode von OracleCommand gibt OracleDataReader für REF CURSOR zurück.

Wenn ihr OracleCommand mehrere REF CURSORS zurückgibt, fügen Sie mehrere Ausgabeparameter hinzu. Sie können auf die verschiedenen REF CURSORs zugreifen, indem Sie die OracleCommand.ExecuteReader() Methode aufrufen. Der Aufruf von ExecuteReader() gibt einen OracleDataReader zurück, der auf den ersten REF CURSOR-Datentyp verweist. Anschließend können Sie die OracleDataReader.NextResult() Methode aufrufen, um auf nachfolgende REF CURSORs zuzugreifen. Obwohl die Parameter in Ihrer OracleCommand.Parameters Auflistung den REF CURSOR-Ausgabeparametern nach Namen entsprechen, greift dies OracleDataReader auf sie in der Reihenfolge zu, in der sie der Parameters Auflistung hinzugefügt wurden.

Betrachten Sie z. B. das folgende Oracle-Paket und den Pakettext.

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;

Mit dem folgenden Code wird ein OracleCommand-Objekt erstellt, das die REF CURSORs aus dem vorherigen Oracle-Paket zurückgibt, indem der OracleType.Cursor-Sammlung zwei Parameter vom Typ OracleCommand.Parameters hinzugefügt werden.

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 Code werden die Ergebnisse des vorherigen Befehls mithilfe der Methode Read() und NextResult() von OracleDataReader zurückgegeben. Die REF CURSOR-Parameter werden in der Reihenfolge 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 vorherige Befehl verwendet, um ein DataSet Element mit den Ergebnissen des Oracle-Pakets aufzufüllen.

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

Hinweis

Um eine OverflowException zu vermeiden, empfehlen wir Ihnen, auch die Konvertierung vom Oracle NUMBER-Typ in einen gültigen .NET Framework-Typ vorzunehmen, bevor Sie den Wert in einem DataRow speichern. Mit dem FillError Ereignis können Sie ermitteln, ob eine OverflowException aufgetreten ist. Weitere Informationen zum FillError Ereignis finden Sie unter Behandeln von DataAdapter-Ereignissen.

Siehe auch