21 Haziran 2016 Salı

DataReader

Giriş
Tüm DataReader nesneleri IDataReader arayüzünden kalıtır. DataReader isimli soyut bir sınıf yoktur. SqlDataReader, OleDbDataReader (MS Access için), OracleDataReader, SQLiteDataReader en çok karşımıza çıkan sınıflar.

SQLiteDataReader System.Data.SQLite namespace içinde. Bu namespace için .Net ile gelmeyen DLL'leri projeye eklemek gerekiyor.

DataReader veritabanını aynı bir iterator gibi ileriye doğru dolaşmamızı sağlar. SQL gözlüğüyle bakarsak bir cursor gibidir. Select cümleleri ile çalışır.

Nasıl Elde Ederiz?
DbCommand nesnesinin ExecuteReader metodunu kullanırız.
SqlConnection connection = new SqlConnection(...);
SqlCommand selectCommand = new SqlCommand(selectStatement, connection);
connection.Open();
SqlDataReader reader = selectCommand.ExecuteReader();
FieldCount Alanı - Sütun Sayısı
Sütun yani alan sayısını şöyle alırız.
reader.FieldCount;
HasRows - Alanı 
Reader'da satır olup olmadığını döner.
if (reader != null && reader.HasRows) 
{
   while (reader.Read()) 
   {
      ...
   }
}
IsDbNull metodu
Read çağrısından sonra belirtilen sütunun null olup olmadığını döner. Şöyle yaparız.
if (!reader.IsDBNull(1)) {...}

Read Metodu
Sınıf şöyle kullanılır.
using(SqlDataReader rdr = cmd.ExecuteReader())
{
    while (rdr.Read())
    {
        var myString = rdr.GetString(0); //first column of the result.
        
    }
}
Eğer sütun numaraları değil de sütun isimleri kullanılsın istiyorsak şöyle yapabiliriz.

public Config(SqlDataReader sdr) {
    for (int i = 0; i < sdr.FieldCount; i++) if (!sdr.IsDBNull(i)) {
        switch (sdr.GetName(i)) {
            case 'Id': Id = sdr.GetInt32(i); break;
            ...
        }
    }
}
yield yöntemi
Bazı kodlarda DataReader IEnumerable gibi kullanılıyor.
IEnumerable<IDataRecord> GetRecords()
{
    SqlConnection myConnection = new SqlConnection(@"...");
    SqlCommand myCommand = new SqlCommand(@"...", myConnection);
    myCommand.CommandType = System.Data.CommandType.Text;
    myReader = myCommand.ExecuteReader(CommandBehavior.CloseConnection);
    try
       {
          while (myReader.Read())
          {
            yield return myReader;          
          }
        }
    finally
        {
            myReader.Close();
        }
}
Bu metod şöyle çağrılır
void AnotherMethod()
{
    foreach(var rec in GetRecords())
    {
       i++;
       System.Console.WriteLine(rec.GetString(1));
       if (i == 5)
         break;
  }
}
Bu yöntem veritabanına bağlantıyı tüm satırlar çekilinceye kadar açık tutar. Spring'deki gibi callback yöntemleri ile liste doldurmak veya bir başka metodu tetiklemek mümkün. Liste doldurmak için şöyle yaparız.
IEnumerable<T> GetRecords<T>(Func<IDataRecord,T> extractor)
{
    // ...
     var result = new List<T>();
     try
     {
       while (myReader.Read())
       {
         result.Add(extractor(myReader));         
       }
     }
     finally
     {
         myReader.Close();
     }
     return result;
}
Callback çağırmak için şöyle yaparız.
void GetRecords(Action<IDataRecord> callback)
{
    // ...
      while (myReader.Read())
      {
        callback(myReader);
      }
}
Benzer mantık C++ kodlarında da var.
template<typename Action, typename ...Args>
void execute(Args... param, Action action)
{
  // STUFF TO SET up connection.
  // Start retrieving rows.


  while(row = results->getNextRow())
  {
    call(action, row);
  }
}
GetOrdinal
Verilen sütunu isminin sırasını döndürür.
TimeSpan t = ((SqlDataReader)reader).GetTimeSpan(reader.GetOrdinal("MyColumn"));
Bracket Operator - Sütunlara Erişim İçin Sütun İsmi
Sütun numarasını bilmeden sadece isim ile erişebiliriz.
SQLiteDataReader reader = ...;
if (reader["expr1"] != DBNull.Value)
{
  name= reader.GetString(0);
}
Bracket Operator - Sütunlara Erişim İçin Sütun Numarası
Şöyle yaparız.
string address = reader[1] as string;
GetBytes metodu
Bu metod ile blob gibi alanlar stream gibi okunabilir.
long bytesRead = sdr.GetBytes(0, readPosition, buffer, offset, count);
GetDecimal metodu
Şöyle yaparız. G ile default formatlama yapılır.
var str = reader.GetDecimal(0).ToString("G");
GetTimeSpan metodu
Şöyle yaparız.
TimeSpan myTimeSpan = ((SqlDataReader)reader).GetTimeSpan(0);
GetString metodu
Şöyle yaparız.
reader.GetString(0);
GetValue metodu
Sınıfın aynı zamanda Object dönen GetValue metodu da var. Bu metod weakly typed.

NextResult metodu
İki tane select cümlesi varsa, ikinic veri setine geçmemizi sağlar. Şöyle yaparız.
reader.NextResult();
DataReader ve Connection
DataReader kapatılıncaya kadar connection açık tutulur. Connection başkasıyla paylaşılamaz.

Connection nesnesi mi using içinde mi kullanılmalı yoksa DataReader nesnesi mi using içinde mi kullanılmalı emin değilim.

MSDN örneklerinde connection using içinde kullanılıyor ve DataReader'ın Close() metodu çağrılmıyor.

DataReader ve Timeout
Eğer okunacak veri miktarı fazla ise DataReader Timeout hatası verebilir. Okumaya başlamadan önce Command nesnesinin timeout değerini ayarlamak gerekir. Mesela 3 dakika şöyle atanır
using (SqlCommand command = new SqlCommand(q, connection))
{
  command.CommandTimeout = 180;
  using (SqlDataReader reader = command.ExecuteReader())
  {
    if (reader.HasRows)
    {
      while (reader.Read())
      {
        dataList .Add(reader.GetString(0));
      }
    }
  }
}

CommandBehavior Nedir
Reader nesnemizin nasıl çalışacağını belirtir. Tek bir satır okumak istiyorsak SqlCommand'i şöyle kullanırız.
SqlDataReader reader = selectCommand.ExecuteReader(CommandBehavior.SingleRow);




Hiç yorum yok:

Yorum Gönder