Dela via


Hämta data med hjälp av en DataReader

Om du vill hämta data med hjälp av en DataReader skapar du en instans av kommandoobjektet och skapar sedan en DataReader genom att anropa Command.ExecuteReader för att hämta rader från en datakälla. DataReader tillhandahåller en obufferderad dataström som gör det möjligt för procedurlogik att effektivt bearbeta resultat från en datakälla sekventiellt. DataReader är ett bra val när du hämtar stora mängder data eftersom data inte cachelagras i minnet.

I följande exempel visas hur du använder en DataReader, där reader representerar en giltig DataReader och command representerar ett giltigt kommandoobjekt.

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

Använd metoden DataReader.Read för att hämta en rad från frågeresultatet. Du kan komma åt varje kolumn i den returnerade raden genom att skicka namnet eller ordningstalet för kolumnen till DataReader. Men för bästa prestanda tillhandahåller DataReader en serie metoder som gör att du kan komma åt kolumnvärden i deras interna datatyper (GetDateTime, GetDouble, GetGuid, GetInt32 och så vidare). En lista över typbaserade åtkomstmetoder för dataleverantörsspecifika DataReaders finns i OleDbDataReader och SqlDataReader. Om du använder de inskrivna åtkomstmetoderna när du vet att den underliggande datatypen minskar mängden typkonvertering som krävs när du hämtar kolumnvärdet.

Följande exempel itererar genom ett DataReader-objekt och returnerar två kolumner från varje rad.

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

Stänga DataReader

Anropa alltid metoden Stäng när du är klar med DataReader-objektet .

Om kommandot innehåller utdataparametrar eller returvärden är dessa värden inte tillgängliga förrän DataReader har stängts.

Även om en DataReader är öppen används Anslut ion uteslutande av dataläsaren. Du kan inte köra några kommandon för Anslut ion, inklusive att skapa en annan DataReader, förrän den ursprungliga DataReader har stängts.

Kommentar

Anropa inte Stäng eller Ta bort på en Anslut ion, en DataReader eller något annat hanterat objekt i metoden Slutför i din klass. I en finalizer släpper du bara ohanterade resurser som klassen äger direkt. Om klassen inte äger några ohanterade resurser ska du inte ta med metoden Slutför i klassdefinitionen. Mer information finns i Skräpinsamling.

Hämtar flera resultatuppsättningar med NextResult

Om DataReader returnerar flera resultatuppsättningar anropar du metoden NextResult för att iterera genom resultatuppsättningarna sekventiellt. I följande exempel visas bearbetningen SqlDataReader av resultatet av två SELECT-instruktioner med hjälp av ExecuteReader metoden.

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

Hämta schemainformation från DataReader

När en DataReader är öppen kan du hämta schemainformation om den aktuella resultatuppsättningen med metoden GetSchemaTable . GetSchemaTable returnerar ett DataTable objekt fyllt med rader och kolumner som innehåller schemainformationen för den aktuella resultatuppsättningen. DataTable innehåller en rad för varje kolumn i resultatuppsättningen. Varje kolumn i schematabellen mappar till en egenskap för kolumnerna som returneras i raderna i resultatuppsättningen, där ColumnName är namnet på egenskapen och värdet för kolumnen är värdet för egenskapen. I följande exempel skrivs schemainformationen för DataReader ut.

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

Arbeta med OLE DB-kapitel

Hierarkiska raduppsättningar eller kapitel (OLE DB-typ DBTYPE_HCHAPTER, ADO-typ adChapter) kan hämtas med hjälp av OleDbDataReader. När en fråga som innehåller ett kapitel returneras som en DataReader returneras kapitlet som en kolumn i dataläsaren och exponeras som ett DataReader-objekt.

ADO.NET DataSet kan också användas för att representera hierarkiska rader med hjälp av överordnade och underordnade relationer mellan tabeller. Mer information finns i DataSets, DataTables och DataViews.

I följande kodexempel används MSDataShape-providern för att generera en kapitelkolumn med beställningar för varje kund i en lista över kunder.

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

Returnera resultat med Oracle REF CURSORs

.NET Framework-dataprovidern för Oracle stöder användning av Oracle REF CURSORs för att returnera ett frågeresultat. En Oracle REF CURSOR returneras som en OracleDataReader.

Du kan hämta ett OracleDataReader objekt som representerar en Oracle REF CURSOR med hjälp ExecuteReader av metoden . Du kan också ange en OracleCommand som returnerar en eller flera Oracle REF CURSORs som SelectCommand för en OracleDataAdapter som används för att fylla i en DataSet.

Om du vill komma åt en REFERENSMARKÖR som returneras från en Oracle-datakälla skapar du en OracleCommand för din fråga och lägger till en utdataparameter som refererar till REFERENSMARKÖR till Parameters samlingen av din OracleCommand. Namnet på parametern måste matcha namnet på REF CURSOR-parametern i din fråga. Ange parametertypen till OracleType.Cursor. Metoden OracleCommand.ExecuteReader() för din OracleCommand returnerar en OracleDataReader för REFERENSMARKÖREN.

Om du OracleCommand returnerar flera REFERENSMARKÖRer lägger du till flera utdataparametrar. Du kan komma åt de olika REFERENS-CURSOR:erna genom att anropa OracleCommand.ExecuteReader() metoden. Anropet till ExecuteReader() returnerar en OracleDataReader referens till den första REFERENSMARKÖREN. Du kan sedan anropa OracleDataReader.NextResult() metoden för att komma åt efterföljande REF CURSORs. Även om parametrarna i samlingen OracleCommand.Parameters matchar REF CURSOR-utdataparametrarna efter namn, kommer de OracleDataReader åt dem i den ordning de lades till Parameters i samlingen.

Tänk till exempel på följande Oracle-paket och 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;

Följande kod skapar en OracleCommand som returnerar REF CURSORs från föregående Oracle-paket genom att lägga till två parametrar av typen OracleType.Cursor i OracleCommand.Parameters samlingen.

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;  

Följande kod returnerar resultatet från föregående kommando med metoderna Read() och NextResult() i OracleDataReader. REFERENSMARKÖRparametrarna returneras i ordning.

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

I följande exempel används föregående kommando för att fylla i ett DataSet med resultatet av Oracle-paketet.

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

Kommentar

För att undvika en OverflowException rekommenderar vi att du även hanterar alla konverteringar från Oracle NUMBER-typen till en giltig .NET Framework-typ innan du lagrar värdet i en DataRow. Du kan använda FillError händelsen för att avgöra om en OverflowException har inträffat. Mer information om händelsen finns i FillError Hantera DataAdapter-händelser.

Se även