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:
Data DbNull