107 Stimmen

Wie erhält man die Anzahl der Zeilen mit SqlDataReader in C#

Meine Frage ist, wie man die Anzahl der Zeilen, die von einer Abfrage mit SqlDataReader in C#. Ich habe einige Antworten zu diesem Thema gesehen, aber keine war klar definiert, außer einer, die besagt, dass man eine while-Schleife mit Read() Methode und erhöhen einen Zähler.

Mein Problem ist, dass ich versuche, ein mehrdimensionales Array mit der ersten Zeile zu füllen, die die Spaltenüberschrift Namen und jede Zeile nach, dass die Zeilendaten zu sein.

Ich weiß, dass ich nur Dump das Zeug in einer Liste-Steuerelement und nicht darum kümmern, aber für meine eigenen persönlichen Erbauung und ich möchte auch die Daten in und aus dem Array ziehen, wie ich wählen und es in verschiedenen Formaten anzeigen.

Ich glaube also, ich kann nicht die Read() und dann den ++ Weg zu erhöhen, weil das bedeutet, dass ich die Read() und öffnen Sie dann Read() erneut, um die Anzahl der Zeilen und dann der Spalten zu erhalten.

Das ist nur ein kleines Beispiel für das, was ich meine:

int counter = 0;    

while (sqlRead.Read())
{
    //get rows
    counter++
}

und dann eine for-Schleife, die die Spalten durchläuft und

something.Read();

int dbFields = sqlRead.FieldCount;

for (int i = 0; i < dbFields; i++)
{
   // do stuff to array
}

106voto

Henk Holterman Punkte 249753

Es gibt nur zwei Möglichkeiten:

  • Finden Sie es heraus, indem Sie alle Zeilen lesen (und dann können Sie sie genauso gut speichern)

  • vorher eine spezielle SELECT COUNT(*)-Abfrage durchführen.

Zweimal durch die DataReader-Schleife zu gehen ist wirklich teuer, Sie müssten die Abfrage erneut ausführen.

Und (dank Pete OHanlon) ist die zweite Option nur dann parallelitätssicher, wenn Sie eine Transaktion mit einem Snapshot-Isolationslevel verwenden.

Da Sie am Ende ohnehin alle Zeilen im Speicher ablegen wollen, ist die einzig sinnvolle Option, alle Zeilen in einem flexiblen Speicher ( List<> o DataTable ) und kopieren Sie dann die Daten in ein beliebiges Format. Die In-Memory-Operation wird immer viel effizienter sein.

10voto

Pit Ming Punkte 389

Wenn Sie nicht alle Zeilen abrufen müssen und eine doppelte Abfrage vermeiden wollen, können Sie vielleicht so etwas versuchen:

using (var sqlCon = new SqlConnection("Server=127.0.0.1;Database=MyDb;User Id=Me;Password=glop;"))
      {
        sqlCon.Open();

        var com = sqlCon.CreateCommand();
        com.CommandText = "select * from BigTable";
        using (var reader = com.ExecuteReader())
        {
            //here you retrieve what you need
        }

        com.CommandText = "select @@ROWCOUNT";
        var totalRow = com.ExecuteScalar();

        sqlCon.Close();
      }

Möglicherweise müssen Sie eine Transaktion hinzufügen. Ich bin mir nicht sicher, ob die Wiederverwendung desselben Befehls automatisch eine Transaktion hinzufügen wird...

8voto

Daniel Segan Punkte 184

Wie oben beschrieben, könnte ein Datensatz oder ein typisierter Datensatz eine gute temporäre Struktur sein, die Sie für Ihre Filterung verwenden könnten. Ein SqlDataReader ist dazu gedacht, die Daten sehr schnell zu lesen. Während Sie sich in der while()-Schleife befinden, sind Sie immer noch mit der DB verbunden und sie wartet darauf, dass Sie das nächste Ergebnis lesen/verarbeiten, bevor sie weitergeht. In diesem Fall könnten Sie eine bessere Leistung erzielen, wenn Sie alle Daten einlesen, die Verbindung zur DB schließen und die Ergebnisse "offline" verarbeiten.

Die Leute scheinen Datensätze zu hassen, also könnte das oben genannte auch mit einer Sammlung von stark typisierten Objekten gemacht werden.

7voto

Pete OHanlon Punkte 9009

Sie können die Anzahl der Zeilen nicht direkt von einem Datenleser abrufen, da es sich um einen so genannten Firehose-Cursor handelt, d. h. die Daten werden zeilenweise auf der Grundlage des durchgeführten Lesevorgangs gelesen. Ich würde davon abraten, 2 Lesevorgänge für die Daten durchzuführen, da sich die Daten zwischen den beiden Lesevorgängen möglicherweise geändert haben und Sie daher unterschiedliche Ergebnisse erhalten würden.

Sie könnten die Daten in eine temporäre Struktur einlesen und diese anstelle des zweiten Lesevorgangs verwenden. Alternativ müssen Sie den Mechanismus, mit dem Sie die Daten abrufen, ändern und stattdessen etwas wie eine DataTable verwenden.

7voto

mehdi Punkte 573

Zur Vervollständigung der Pit-Antwort und für eine bessere Leistung: alles in einer Abfrage erhalten und NextResult-Methode verwenden.

using (var sqlCon = new SqlConnection("Server=127.0.0.1;Database=MyDb;User Id=Me;Password=glop;"))
{
    sqlCon.Open();
    var com = sqlCon.CreateCommand();
    com.CommandText = "select * from BigTable;select @@ROWCOUNT;";
    using (var reader = com.ExecuteReader())
    {
        while(reader.Read()){
            //iterate code
        }
        int totalRow = 0 ;
        reader.NextResult();
        if(reader.Read()){
            totalRow = (int)reader[0];
        }
    }
    sqlCon.Close();
}

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X