Adatok lekérése DataReader használatával

Az adatok DataReaderrel való lekéréséhez hozzon létre egy objektumpéldánytCommand, majd hozzon létre egy DataReaderparancsot a Command.ExecuteReader meghívásával, hogy sorokat kérjen le egy adatforrásból. A DataReader rendszer nem felügyelt adatfolyamot biztosít, amely lehetővé teszi az eljáráslogika számára az adatforrások eredményeinek egymás utáni hatékony feldolgozását. DataReader nagy mennyiségű adat lekérése esetén jó választás, mert az adatok nincsenek gyorsítótárazva a memóriában.

Az alábbi példa egy DataReader használatát szemlélteti, amely reader egy érvényes DataReadert jelöl, és command egy érvényes parancsobjektumot jelöl.

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

A DataReader.Read metódussal beolvashat egy sort a lekérdezés eredményeiből. A visszaadott sor egyes oszlopait úgy érheti el, hogy átadja az oszlop nevét vagy sorszámát a DataReadernek. A legjobb teljesítmény érdekében azonban a DataReader metódusok sorozata lehetővé teszi az oszlopértékek elérését a natív adattípusokban (GetDateTime, GetDouble, GetGuid, GetInt32 stb.). Az adatszolgáltatóspecifikus DataReaders típusozott kiegészítő módszereinek listáját lásd OleDbDataReader és SqlDataReader. Ha ismeri a mögöttes adattípust, a beírt kiegészítő módszerek használata csökkenti az oszlopérték lekéréséhez szükséges típusátalakítás mennyiségét.

Az alábbi példa egy DataReader objektumon halad végig, és két oszlopot ad vissza minden sorból.

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

A DataReader bezárása

Mindig hívja meg a metódust Close , ha befejezte az DataReader objektum használatát.

Ha kimeneti Command paramétereket vagy visszatérési értékeket tartalmaz, ezek az értékek nem érhetők el, amíg be nem zárja őket DataReader .

Míg a DataReader nyitva van, a Connection kizárólag az adott DataReader-t használja. Nem hajthat végre parancsokat a kapcsolathoz, beleértve egy másik DataReader létrehozását is, amíg az eredeti DataReader be nem záródik.

Megjegyzés:

Az osztály metódusában ne hívja meg a Close vagy a Dispose egy Kapcsolat, egy DataReader, vagy bármilyen más felügyelt objektum esetén. A véglegesítőben csak az osztály tulajdonában lévő nem felügyelt erőforrásokat szabadíthatja fel. Ha az osztály nem rendelkezik nem felügyelt erőforrásokkal, ne foglaljon bele metódust Finalize az osztálydefinícióba. További információ: Szemétgyűjtés.

Több eredményhalmaz beolvasása a NextResult használatával

Ha a DataReader függvény több eredményhalmazt ad vissza, hívja meg a NextResult metódust, hogy egymás után haladjon át az eredményhalmazokon. Az alábbi példa bemutatja, hogyan dolgozza fel a SqlDataReader két SELECT utasítás eredményeit a ExecuteReader metódus használatával.

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

Sémaadatok lekérése a DataReaderből

Amíg a DataReader meg van nyitva, a GetSchemaTable metódus használatával lekérheti az aktuális eredményhalmaz sémaadatait. GetSchemaTable Az DataTable aktuális eredményhalmaz sémaadatait tartalmazó sorokkal és oszlopokkal kitöltött objektumot ad vissza. Az DataTable eredményhalmaz minden oszlopához egy sort tartalmaz. A sématábla minden oszlopa az eredményhalmaz soraiban visszaadott oszlopok egyik tulajdonságához van leképezve, ahol a ColumnName tulajdonság neve, az oszlop értéke pedig a tulajdonság értéke. Az alábbi példa a DataReader sémaadatait írja le.

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

OLE DB-fejezetek használata

Hierarchikus sorkészletek vagy fejezetek (OLE DB-típus DBTYPE_HCHAPTER, ADO-típus adChapter) lekérhetők a OleDbDataReader. Ha egy fejezetet tartalmazó lekérdezés DataReaderként kerül visszaadásra, a fejezet oszlopként jelenik meg benne DataReader, és DataReader objektumként kezelhető.

A ADO.NET DataSet hierarchikus sorhalmazok ábrázolására is használható a táblák közötti szülő-gyermek kapcsolatok használatával. További információ: DataSets, DataTables és DataViews.

Az alábbi példakód az MSDataShape-szolgáltatót használja a rendelések fejezetoszlopának létrehozásához az ügyfelek listájában.

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

Eredmények visszaadása Oracle REF CURSOR-okkal

Az Oracle .NET-keretrendszer adatszolgáltatója támogatja az Oracle REF CURSORs használatát a lekérdezés eredményének visszaadásához. Az Oracle REF CURSOR mint egy OracleDataReader van visszaadva.

Az OracleDataReader metódussal egy ExecuteReader objektumot kérhet le, amely egy Oracle REF CURSOR-t képvisel. Megadhat egy OracleCommand is, amely egy vagy több Oracle REF CURSOR-t ad vissza a SelectCommand kitöltéséhez használt OracleDataAdapterDataSet számára.

Az Oracle-adatforrásból visszaadott REF CURSOR eléréséhez hozzon létre egy OracleCommand az Ön lekérdezéséhez, és adjon hozzá egy kimeneti paramétert, amely a REF CURSOR-ra hivatkozik az Parameters gyűjteményéhez az Ön OracleCommand-jének. A paraméter nevének meg kell egyeznie a LEKÉRDEZÉS REF CURSOR paraméterének nevével. Állítsa be a paraméter típusát a következőre OracleType.Cursor: . A OracleCommand.ExecuteReader() metódus OracleCommand a REF CURSOR-hoz ad vissza egy OracleDataReader értéket.

Ha több REF-KURZORT ad OracleCommand vissza, adjon hozzá több kimeneti paramétert. A különböző REF CURSOR-okat a OracleCommand.ExecuteReader() metódus meghívásával érheti el. A ExecuteReader() hívás egy OracleDataReader-et ad vissza, amely az első REF CURSOR-ra hivatkozik. Ezután meghívhatja a(z) OracleDataReader.NextResult() metódust, hogy elérje a következő REF CURSOR-okat. Bár a paraméterek a OracleCommand.Parameters gyűjteményben név szerint egyeznek a REF CURSOR kimeneti paraméterekkel, a OracleDataReader a gyűjteményhez való hozzáadásuk sorrendjében éri el őket Parameters.

Vegyük például az alábbi Oracle-csomagot és csomagtörzset.

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;

Az alábbi kód létrehoz egy OracleCommand, amely visszaadja az előző Oracle-csomag REF CURSOR-jait, miközben hozzáad két OracleType.Cursor típusú paramétert a OracleCommand.Parameters gyűjteményhez.

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;

Az alábbi kód az előző parancs eredményeit adja vissza a Read() és a NextResult() metódusok használatával a OracleDataReader-ban. A REF CURSOR paramétereket a rendszer sorrendben adja vissza.

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

Az alábbi példa az előző parancsot használja az Oracle-csomag eredményeinek feltöltéséhez DataSet .

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

Megjegyzés:

Az OverflowException elkerülése érdekében azt javasoljuk, hogy az Oracle NUMBER típusból érvényes .NET Framework típusra történő konvertálást is kezelje, mielőtt az értéket egy DataRow tárolja. Az esemény FillError használatával megállapíthatja, hogy történt-e OverflowException. Az eseményről további információt a FillErrorDataAdapter-események kezelése című témakörben talál.

Lásd még