C # 'da SqlDataReader kullanarak satır sayısı nasıl elde edilir


98

Sorum, SqlDataReaderC # kullanarak bir sorgu tarafından döndürülen satır sayısını nasıl elde edeceğidir . Bununla ilgili bazı yanıtlar gördüm, ancak Read()yöntemle bir süre döngüsü yapmayı ve bir sayacı artırmayı belirten biri dışında hiçbiri açıkça tanımlanmadı .

Benim sorunum, çok boyutlu bir diziyi ilk satırın sütun başlığı adları olacak şekilde ve ondan sonraki her satırın satır verileri olacak şekilde doldurmaya çalışıyorum.

Öğeleri bir Liste kontrolüne atabileceğimi ve bunun için endişelenmeyeceğimi biliyorum, ancak kendi kişisel düzenlemem için ve ayrıca seçip farklı formatlarda görüntülerken veriyi dizinin içine ve dışına çekmek istiyorum.

Bu yüzden, Read()ve sonra artım ++ yöntemini yapamayacağımı düşünüyorum çünkü bu , satır sayısını ve ardından sütun verilerini almak için Read()açıp Read()tekrar açmam gerektiği anlamına geliyor .

Bahsettiğim şeyin sadece küçük bir örneği:

int counter = 0;    

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

ve sonra sütunların üzerinden geçip pop

something.Read();

int dbFields = sqlRead.FieldCount;

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

Yanıtlar:


97

Yalnızca iki seçenek vardır:

  • Tüm satırları okuyarak öğrenin (ve sonra onları da saklayabilirsiniz)

  • önceden özelleştirilmiş bir SELECT COUNT (*) sorgusu çalıştırın.

DataReader döngüsünden iki kez geçmek gerçekten pahalıdır, sorguyu yeniden yürütmeniz gerekir.

Ve (Pete OHanlon sayesinde), ikinci seçenek yalnızca Snapshot izolasyon seviyesine sahip bir işlem kullandığınızda eşzamanlılık açısından güvenlidir.

Zaten tüm satırları bellekte depolamak istediğiniz için tek mantıklı seçenek, tüm satırları esnek bir depolamada ( List<>veya DataTable) okumak ve ardından verileri istediğiniz herhangi bir biçime kopyalamaktır. Bellek içi işlem her zaman çok daha verimli olacaktır.


5
Henk haklı: DataReader'ın satır sayısını almanıza izin veren bir üyesi yok çünkü o sadece ileriye dönük bir okuyucu. İlk önce sayımı yapmak ve sonra sorguyu yürütmek daha iyidir, belki birden çok sonuçlu bir sorguda veritabanına yalnızca bir kez basarsınız.
flipdoubt

14
Özelleştirilmiş sayımla ilgili sorun, sayının döndürülen satır sayısından farklı olma potansiyelinin olmasıdır, çünkü başka biri verileri döndürülen satırların sayısına yol açacak şekilde değiştirmiştir.
Pete OHanlon

1
Pete, haklısın, pahalı bir İzolasyon Seviyesi gerektirir.
Henk Holterman

1
Hepinize teşekkür ederim! Bu daha net hale geliyor. Öyleyse, tüm bilgileri DataSet'e dökmek veya bir SQL COUNT (*) üzerinden çalıştırmak, depolamak ve ardından gerekli sorguyu çalıştırmak daha mı iyidir? Yoksa çalışan sayımdan ve her şeyi DataSet'te depolamaktan mı bahsediyoruz?
Tomasz Iniewicz

4
Bir RepeatableReadhala kayıtları eklenecek verir, böylece yalıtım düzeyi Eğer bir yalıtım düzeyi kullanılarak çözülmesi gereken, aralık-kilitleme yapmaz Snapshotya Serializable.
Lukazoid

10

Tüm satırı geri almanız gerekmiyorsa ve çift sorgu yapmaktan kaçınmak istiyorsanız, muhtemelen şöyle bir şey deneyebilirsiniz:

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

Aynı komutu tekrar kullanmanın ona otomatik olarak bir işlem ekleyip eklemeyeceğinden emin olmayan bir işlem eklemeniz gerekebilir ...


1
@@ ROWCOUNT her zaman yukarıda çalışan son sorguya dayanıyorsa herkes söyleyebilir mi? Birçok bağlantı sorguları paralel çalıştırıyorsa sorun mu yaşıyorsunuz?
YvesR

1
Yapılması gerekiyor sqlCon.Close();mu? Bunun usingsenin için yapması gerektiğini düşündüm .
mavimsi

1
Okuyucudan veri almadan önce
satır sayısına

8

Yukarıdaki gibi, bir veri kümesi veya yazılan veri kümesi, filtrelemenizi yapmak için kullanabileceğiniz iyi bir geçici yapı olabilir. SqlDataReader, verileri çok hızlı okumak içindir. While () döngüsündeyken hala DB'ye bağlısınız ve devam etmeden önce bir sonraki sonucu okumak / işlemek için yaptığınız her şeyi yapmanızı bekler. Bu durumda, tüm verileri çekerseniz, DB bağlantısını kapatırsanız ve sonuçları "çevrimdışı" olarak işlerseniz daha iyi performans elde edebilirsiniz.

İnsanlar veri kümelerinden nefret ediyor gibi görünüyor, bu nedenle yukarıdakiler, güçlü bir şekilde yazılmış nesnelerin bir koleksiyonuyla da yapılabilir.


2
DataSets'i çok seviyorum, çünkü bunlar iyi yazılmış ve tablo tabanlı verilerin son derece yararlı genel bir temsilidir. Garip bir şekilde, ORM için DataSet'ten kaçınan çoğu insanın, mümkün olduğunca genel (genellikle anlamsız) olması için kendi kodlarını yazmaya çalışan aynı kişiler olduğunu fark ettim.
MusiGenesis

5
Daniel, 'yukarıda' başka bir yanıta atıfta bulunmak için iyi bir yol değil.
Henk Holterman

6

Doğrudan bir veri okuyucudan satır sayısı alamazsınız çünkü bu, yangın hortumu imleci olarak bilinir - bu, verilerin, gerçekleştirilen okumaya göre satır bazında okunduğu anlamına gelir. Veriler üzerinde 2 okuma yapmamanızı tavsiye ederim çünkü verilerin 2 okuma arasında değişme potansiyeli vardır ve bu nedenle farklı sonuçlar alırsınız.

Yapabileceğiniz şey, verileri geçici bir yapı halinde okumak ve bunu ikinci okuma yerine kullanmaktır. Alternatif olarak, verileri aldığınız mekanizmayı değiştirmeniz ve bunun yerine DataTable gibi bir şey kullanmanız gerekecektir.


5

Pit yanıtını tamamlamak ve daha iyi performans için: hepsini tek bir sorguda alın ve NextResult yöntemini kullanın.

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

1

Ayrıca en iyi sonucu döndürmem gerektiğinde, ancak aynı zamanda sorguyla eşleşen toplam satırları elde etmek istediğim bir durumla da karşılaştım. nihayet bu çözüme ulaşıyorum:

   public string Format(SelectQuery selectQuery)
    {
      string result;

      if (string.IsNullOrWhiteSpace(selectQuery.WherePart))
      {
        result = string.Format(
@"
declare @maxResult  int;
set @maxResult = {0};

WITH Total AS
(
SELECT count(*) as [Count] FROM {2}
)
SELECT top (@maxResult) Total.[Count], {1} FROM Total, {2}", m_limit.To, selectQuery.SelectPart, selectQuery.FromPart);
      }
      else
      {
        result = string.Format(
@"
declare @maxResult  int;
set @maxResult = {0};

WITH Total AS
(
SELECT count(*) as [Count] FROM {2} WHERE {3}
)
SELECT top (@maxResult) Total.[Count], {1} FROM Total, {2} WHERE {3}", m_limit.To, selectQuery.SelectPart, selectQuery.FromPart, selectQuery.WherePart);
      }

      if (!string.IsNullOrWhiteSpace(selectQuery.OrderPart))
        result = string.Format("{0} ORDER BY {1}", result, selectQuery.OrderPart);

      return result;
    }
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.