Pobieranie danych przy użyciu elementu DataReader

Aby pobrać dane przy użyciu elementu DataReader, utwórz wystąpienie obiektu Command , a następnie utwórz element DataReader , wywołując polecenie Command.ExecuteReader w celu pobrania wierszy ze źródła danych. Element DataReader udostępnia niebuforowany strumień danych, który umożliwia logiki proceduralnej efektywne przetwarzanie wyników ze źródła danych sekwencyjnie. Element DataReader jest dobrym wyborem podczas pobierania dużych ilości danych, ponieważ dane nie są buforowane w pamięci.

Poniższy przykład ilustruje użycie elementu DataReader, gdzie reader reprezentuje prawidłowy element DataReader i command reprezentuje prawidłowy obiekt command.

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

Użyj metody DataReader.Read, aby uzyskać wiersz z wyników zapytania. Dostęp do każdej kolumny zwróconego wiersza można uzyskać, przekazując nazwę lub numer porządkowy kolumny do elementu DataReader. Jednak w celu uzyskania najlepszej wydajności funkcja DataReader udostępnia szereg metod, które umożliwiają dostęp do wartości kolumn w ich natywnych typach danych (GetDateTime, GetDouble, GetGuid, GetInt32 itd.). Aby uzyskać listę typowych metod dostępu dla elementów DataReaders specyficznych dla dostawcy danych, zobacz OleDbDataReader i SqlDataReader. Użycie typowych metod dostępu, gdy wiadomo, że bazowy typ danych zmniejsza ilość konwersji typu wymaganej podczas pobierania wartości kolumny.

Poniższy przykład iteruje przez obiekt DataReader i zwraca dwie kolumny z każdego wiersza.

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("{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

Zamykanie elementu DataReader

Zawsze wywołaj metodę Close po zakończeniu korzystania z obiektu DataReader .

Jeśli polecenie zawiera parametry wyjściowe lub zwracane wartości, te wartości nie są dostępne do momentu zamknięcia elementu DataReader.

Gdy element DataReader jest otwarty, Połączenie ion jest używany wyłącznie przez ten element DataReader. Nie można wykonać żadnych poleceń dla Połączenie ion, w tym tworzenia innego elementu DataReader, dopóki oryginalny element DataReader nie zostanie zamknięty.

Uwaga

Nie należy wywoływać metody Close lub Dispose na Połączenie ion, DataReader ani innych zarządzanych obiektów w metodzie Finalize klasy. W finalizatorze zwalniaj tylko niezarządzane zasoby, które należą do klasy bezpośrednio. Jeśli klasa nie jest właścicielem żadnych zasobów niezarządzanych, nie uwzględnij metody Finalize w definicji klasy. Aby uzyskać więcej informacji, zobacz Odzyskiwanie pamięci.

Pobieranie wielu zestawów wyników przy użyciu polecenia NextResult

Jeśli element DataReader zwraca wiele zestawów wyników, wywołaj metodę NextResult , aby iterować zestawy wyników sekwencyjnie. Poniższy przykład przedstawia SqlDataReader przetwarzanie wyników dwóch instrukcji SELECT przy użyciu ExecuteReader metody .

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{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

Pobieranie informacji o schemacie z elementu DataReader

Gdy element DataReader jest otwarty, możesz pobrać informacje o schemacie dotyczące bieżącego zestawu wyników przy użyciu metody GetSchemaTable. Polecenie GetSchemaTable zwraca DataTable obiekt wypełniony wierszami i kolumnami zawierającymi informacje o schemacie dla bieżącego zestawu wyników. Tabela DataTable zawiera jeden wiersz dla każdej kolumny zestawu wyników. Każda kolumna tabeli schematu jest mapowana na właściwość kolumn zwracanych w wierszach zestawu wyników, gdzie kolumna ColumnName jest nazwą właściwości, a wartość kolumny jest wartością właściwości. Poniższy przykład zapisuje informacje o schemacie dla elementu DataReader.

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

Praca z rozdziałami OLE DB

Hierarchiczne zestawy wierszy lub rozdziały (typ OLE DB DBTYPE_HCHAPTER, typ ADO adChapter), można pobrać przy użyciu .OleDbDataReader Gdy zapytanie zawierające rozdział jest zwracane jako element DataReader, rozdział jest zwracany jako kolumna w tym module DataReader i jest uwidaczniany jako obiekt DataReader.

Zestaw ADO.NET DataSet może również służyć do reprezentowania hierarchicznych zestawów wierszy przy użyciu relacji nadrzędny-podrzędny między tabelami. Aby uzyskać więcej informacji, zobacz DataSets, DataTables i DataViews.

Poniższy przykład kodu używa dostawcy MSDataShape do wygenerowania kolumny rozdziału zamówień dla każdego klienta na liście klientów.

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

Zwracanie wyników za pomocą obiektów CURSOR Oracle REF

Program .NET Framework Dostawca danych dla programu Oracle obsługuje użycie obiektów CURSOR Oracle REF w celu zwrócenia wyniku zapytania. Kursor REF Oracle jest zwracany jako OracleDataReader.

Obiekt reprezentujący kursor REF Oracle można pobrać OracleDataReader przy użyciu ExecuteReader metody . Można również określić obiekt OracleCommand , który zwraca co najmniej jeden element CURSORs Oracle REF jako polecenie SelectCommand używane OracleDataAdapter do wypełnienia DataSetelementu .

Aby uzyskać dostęp do kursora REF zwróconego ze źródła danych Oracle, utwórz element OracleCommand dla zapytania i dodaj parametr wyjściowy odwołujący się do kursora REF do Parameters kolekcji OracleCommandelementu . Nazwa parametru musi być zgodna z nazwą parametru REF CURSOR w zapytaniu. Ustaw typ parametru na OracleType.Cursor. OracleCommand.ExecuteReader() Metoda OracleCommand zwraca wartość OracleDataReader dla kursora REF.

Jeśli zwracasz OracleCommand wiele kursorów REF, dodaj wiele parametrów wyjściowych. Dostęp do różnych metod REF CURSORs można uzyskać, wywołując metodę OracleCommand.ExecuteReader() . Wywołanie metody zwraca ExecuteReader()OracleDataReader odwołanie do pierwszego kursora REF. Następnie można wywołać metodę OracleDataReader.NextResult() w celu uzyskania dostępu do kolejnych metod REF CURSORs. Mimo że parametry w OracleCommand.Parameters kolekcji są zgodne z parametrami wyjściowymi KURSORa REF według nazwy, OracleDataReader uzyskuje do nich dostęp w kolejności, w jakiej zostały dodane do Parameters kolekcji.

Rozważmy na przykład następujący pakiet Oracle i treść pakietu.

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;

Poniższy kod tworzy obiekt OracleCommand , który zwraca odwołania REF CURSORs z poprzedniego pakietu Oracle, dodając dwa parametry typu OracleType.Cursor do OracleCommand.Parameters kolekcji.

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;  

Poniższy kod zwraca wyniki poprzedniego polecenia przy użyciu Read() metod i NextResult() .OracleDataReader Parametry KURSORA REF są zwracane w kolejności.

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

W poniższym przykładzie użyto poprzedniego polecenia, aby wypełnić DataSet element wynikami pakietu Oracle.

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

Uwaga

Aby uniknąć błędu OverflowException, zalecamy również obsługę dowolnej konwersji z typu Oracle NUMBER do prawidłowego typu programu .NET Framework przed zapisaniem wartości w obiekcie DataRow. Możesz użyć zdarzenia FillError , aby określić, czy wystąpił wyjątek OverflowException . Aby uzyskać więcej informacji na FillError temat zdarzenia, zobacz Obsługa zdarzeń dataadapter.

Zobacz też