Lettura dei dati e DbNull

Uno dei problemi che spesso si hanno durante la lettura dei dati tramite Ado è scovare i DbNUll per non cadere nella maggior parte dei casi in InvalidCastException a runtime. Il risultato che se si vogliono fare le cose fatte bene abbiamo a che fare con codice prolisso o codice virtuoso inline che penalizza la leggibilità.

Una cosa interessante che si può fare per ovviare a questo è implementare un wrapper di supporto per il DataRecord. Parlo di DataRecord in quanto sono abituato a leggere i dati con il DataReader... nel caso si usa più spesso il DataAdapter non vedo alcuna controindicazione a replicare un wrapper simile per il DataRow.

L'implementazione del wrapper apparirà un po noiosa... ma fatto una volta è fatto per sempre :-p Si tratterà fondamentalmente di rimappere tutte le funzioni di un DataRecord a cui verranno aggiunte dei metodi aggiuntivi oin modo da creare degli overload per tutti i metodi di recupero dati... vediamo un po nel dettaglio stralci di codice di qllo che ho fatto!

 
 /// Wrapper per IDataRecord. 
 /// Non è necessario che il wrapper implementi anch'esso IDataRecord, ma può tornare comodo ;-p
 public class DataRecordSupport: IDataRecord
 {
  #region Fields
  IDataRecord _dataRecord;
  #endregion
  #region Constructors
  public DataRecordSupport(IDataRecord dataRecord)
  {
   _dataRecord = dataRecord;
  }
  #endregion
  #region IDataRecord Members
  public int GetInt32(int i)
  {
   return _dataRecord.GetInt32(i);
  }
  public object this[string name]
  {
   get
   {
    return _dataRecord[name];
   }
  }
  
  // ...
  // Rimappatura tutti i metodi.
  // ...
  #endregion  
  #region Metodi Aggiuntivi
  
  #region GetValue overloads
  /// Ritorna il valore indicato dal nome del campo. 
  /// Se il valore è DbNull torna il valore di default indicato.
  public object GetValue(string name, object defaultValue)
  {
   int i = GetOrdinal(name);
   return GetValue(i, defaultValue);
  }
  ///  Ritorna il valore indicato dall'indice del campo. 
  ///  Se il valore è DbNull torna il valore di default indicato.
  public object GetValue(int i, object defaultValue)
  {
   object data = _dataRecord[i];
   if(_dataRecord.IsDBNull(i))
   {
    return defaultValue;
   }
   else
   {
    return data;
   }
  }
  #endregion
  #region GetInt32 overloads
  public int GetInt32(string name, int defaultValue)
  {
   int i = GetOrdinal(name);
   return GetInt32(i, defaultValue);
  }
  public int GetInt32(int i, int defaultValue)
  {
   if(IsDBNull(i))
   {
    return defaultValue;
   }
   else
   {
    return GetInt32(i);
   }
  }
  public int GetInt32(string name)
  {
   int i = GetOrdinal(name);
   return GetInt32(i);
  }
  #endregion
  // ...
  // Overloads per tutti i restanti tipi
  // ...
  #endregion    
 }

Come possiamo usare quanto appena scritto? Che benefici possiamo avere? I benefici vanno alla scrittura del codice. Ecco un esempio di utilizzo.

 IDataReader reader = cmd.OpenReader(...);
 while(reader.Read())
 {
 
  /*
  // Codice senza DataRecordSupport... 
  // con sani virtuosismi inline ;-p
  
  int indice = reader["indice"] == DbNUll.Value ? 0 : (int)reader["indice"];
  string descrizione = reader["descrizione"] == DbNUll.Value ? String.Empty : (string)reader["descrizione"];
  datetime unadata = reader["unaData"] == DbNUll.Value ? datetime.Now : (datetime)reader["unaData"];
  */

  DataRecordSupport drs = new DataRecordSupport(reader);
  int indice = drs.GetInt32("indice", 0); 
  string descrizione = drs.GetString("descrizione", string.Empty);
  datetime unadata = drs.GetDateTime("unaData", datetime.Now); 
  
  // ...
 }
 reader.Close();
  
Technorati Tags:
«agosto»
domlunmarmergiovensab
25262728293031
1234567
891011121314
15161718192021
22232425262728
2930311234