Abrufen von Daten mithilfe eines DataReader-Objekts

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 veranschaulicht, wobei einen gültigen DataReader darstellt und command ein gültiges Command-Objekt darstellt.

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 typbasierten Accessormethoden für datenanbieterspezifische DataReader finden Sie unter 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 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();
    }
}
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"

Wenn das DataReader-Objekt nicht mehr benötigt wird, sollten Sie immer die Close-Methode aufrufen.

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 mit 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 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();
        }
    }
}
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 aus dem DataReader

Solange ein DataReader-Objekt geöffnet ist, können Sie mit der GetSchemaTable-Methode Schemainformationen zum aktuellen Resultset abrufen. GetSchemaTable gibt ein -Objekt zurück , das mit Zeilen und Spalten aufgefü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 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]));
            }
        }
    }
}
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 von 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 mithilfe von Über-/Unterordnungsbeziehungen zwischen Tabellen dargestellt zu werden. Weitere Informationen finden Sie unter DataSets, DataTables und DataViews.

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

    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 zur Rückgabe eines Abfrageergebnisses. Ein Oracle-REF CURSOR wird als OracleDataReader zurückgegeben.

Sie können ein Objekt abrufen, OracleDataReader das einen Oracle REF CURSOR darstellt, indem Sie die -Methode ExecuteReader verwenden. Sie können auch einen angeben, OracleCommand der eine oder mehrere Oracle REF CURSORs als OracleCommandOracleDataAdapter für einen zurückgibt, der zum Füllen eines verwendet wird DataSet.

Um auf einen REF CURSOR zu zugreifen, der von einer Oracle-Datenquelle zurückgegeben wird, erstellen Sie einen für Ihre Abfrage, und fügen Sie einen Ausgabeparameter hinzu, OracleCommand der auf den REF CURSOR Parameters in der Auflistung ihrer verweist OracleCommand. Der Name des Parameters muss mit dem Namen des REF CURSOR-Parameters in der Abfrage übereinstimmen. Legen Sie den Typ des Parameters auf fest OracleType.Cursor. Die OracleCommand.ExecuteReader() -Methode von gibt OracleCommand einen für OracleDataReader den REF CURSOR zurück.

Wenn Mehrere OracleCommand REF CURSORs zurückgegeben werden, fügen Sie mehrere Ausgabeparameter hinzu. Sie können auf die verschiedenen REF CURSORs zugreifen, indem Sie die -Methode OracleCommand.ExecuteReader() aufrufen. Der Aufruf von gibt ExecuteReader() einen zurück OracleDataReader , der auf den ersten REF CURSOR-Wert verweisen soll. Anschließend können Sie die -Methode aufrufen OracleDataReader.NextResult() , um auf nachfolgende REF CURSORs zu zugreifen. Obwohl die Parameter in Ihrer OracleCommand.Parameters Auflistung den REF CURSOR-Ausgabeparametern nach Namen entsprechen, greifen die in der Reihenfolge auf sie zu, OracleDataReader in der sie der Auflistung hinzugefügt Parameters 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;

Der folgende Code erstellt eine , OracleCommand die die REF CURSORs aus dem vorherigen Oracle-Paket OracleType.Cursor zurückgibt, indem der Auflistung zwei Parameter vom Typ hinzugefügt OracleCommand.Parameters 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;  

Der folgende Code gibt die Ergebnisse des vorherigen Befehls mithilfe der Methoden Read() und NextResult() des zurück OracleDataReader. 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 mit dem vorherigen Befehl ein DataSet mit den Ergebnissen des Oracle-Pakets aufgefüllt.

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, empfiehlt es sich, vor dem Speichern des Werts in eine auch jede Konvertierung vom Oracle NUMBER-Typ in einen gültigen .NET Framework-Typ zu verarbeiten. Sie können das -Ereignis FillError verwenden, um zu bestimmen, ob eine FillError aufgetreten ist. Weitere Informationen zum Ereignis finden Sie FillError unter FillError.

Weitere Informationen