Gestione di un DateTime DBNull
Domanda
ho visto molte, molte versioni di questo su SO, ma nessuno di loro sembra funzionare abbastanza per le mie esigenze.
I miei dati provengono da un database vendor che permette null per i campi DateTime. In primo luogo io tiro i miei dati in un DataTable.
using (SqlCommand cmd = new SqlCommand(sb.ToString(), conn))
using (SqlDataAdapter da = new SqlDataAdapter(cmd))
{
da.Fill(dt);
}
sto convertendo un DataTable ad un List <> per l'elaborazione.
var equipment = from i in dt.AsEnumerable()
select new Equipment()
{
Id = i.Field<string>("ID"),
BeginDate = i.Field<DateTime>("BeginDate"),
EndDate = i.Field<DateTime>("EndDate"),
EstimatedLife = i.Field<double>("EstimatedLife")
}
Quindi, come faccio a verificare la presenza di DBNull in questo caso? Ho provato a scrivere un metodo.
public DateTime CheckDBNull(object dateTime)
{
if (dateTime == DBNull.Value)
return DateTime.MinValue;
else
return (DateTime)dateTime;
}
Soluzione
Una delle opzioni possibili è conservarlo come un tempo la data annullabile con la sintassi DateTime?
Ecco un link alla MSDN sull'utilizzo tipi nullable
Altri suggerimenti
System.Convert.IsDBNull(value);
o se si dispone di un SqlDataReader
reader.IsDBNull(ordinal);
E fare le vostre proprietà DateTime
essere nullable (DateTime?
) e set null
in caso di DBNull
. Field<T>()
verrà automaticamente fare questo.
Ecco un esempio di codice che uso per leggere datetimes
im sicuro che potrebbe essere scritto meglio ma va bene per me
public DateTime? ReadNullableDateTimefromReader(string field, IDataRecord data)
{
var a = data[field];
if (a != DBNull.Value)
{
return Convert.ToDateTime(a);
}
return null;
}
public DateTime ReadDateTimefromReader(string field, IDataRecord data)
{
DateTime value;
var valueAsString = data[field].ToString();
try
{
value = DateTime.Parse(valueAsString);
}
catch (Exception)
{
throw new Exception("Cannot read Datetime from reader");
}
return value;
}
Ho trovato che il modo più semplice per gestire questa situazione è di lanciare il campo come tipo di dati utilizzando il "come" parola chiave. Questa grande opera per i campi di database che possono essere nulli, ed è bello e semplice.
Ecco maggiori dettagli su questo: getto diretto contro 'come' operatore
Esempio:
IDataRecord record = FromSomeSqlQuerySource;
string nullableString;
DateTime? nullableDateTime;
nullableString = record["StringFromRecord"] as string;
nullableDateTime = record["DateTimeFromRecord"] as DateTime?;
Si dovrebbe usare DataRow["ColumnName"] is DBNull
per confrontare DateTime nullo.
per esempio:.
if(studentDataRow["JoinDate"] is DBNull) { // Do something here }
Ho scritto un metodo di estensione generica che io uso in tutti i miei progetti:
public static object GetValueSafely<T>(this System.Data.DataTable dt, string ColumnName, int index)
{
if (typeof(T) == typeof(int))
{
if (dt.Rows[index][ColumnName] != DBNull.Value)
return dt.Rows[index][ColumnName];
else
return 0;
}
else if (typeof(T) == typeof(double))
{
if (dt.Rows[index][ColumnName] != DBNull.Value)
return dt.Rows[index][ColumnName];
else
return 0;
}
else if (typeof(T) == typeof(decimal))
{
if (dt.Rows[index][ColumnName] != DBNull.Value)
return dt.Rows[index][ColumnName];
else
return 0;
}
else if (typeof(T) == typeof(float))
{
if (dt.Rows[index][ColumnName] != DBNull.Value)
return dt.Rows[index][ColumnName];
else
return 0;
}
else if (typeof(T) == typeof(string))
{
if (dt.Rows[index][ColumnName] != DBNull.Value)
return dt.Rows[index][ColumnName];
else
return string.Empty;
}
else if (typeof(T) == typeof(byte))
{
if (dt.Rows[index][ColumnName] != DBNull.Value)
return dt.Rows[index][ColumnName];
else
return 0;
}
else if (typeof(T) == typeof(DateTime))
{
if (dt.Rows[index][ColumnName] != DBNull.Value)
return dt.Rows[index][ColumnName];
else
return DateTime.MinValue;
}
else if (typeof(T) == typeof(bool))
{
if (dt.Rows[index][ColumnName] != DBNull.Value)
return dt.Rows[index][ColumnName];
else
return false;
}
if (dt.Rows[index][ColumnName] != DBNull.Value)
return dt.Rows[index][ColumnName];
else
return null;
}
Esempio di utilizzo:
private void Example()
{
DataTable dt = GetDataFromDb() // get data from database...
for (int i = 0; i < dt.Rows.Count; i++)
{
Console.WriteLine((DateTime)dt.GetValueSafely<DateTime>("SomeDateColumn", i));
Console.WriteLine((int)dt.GetValueSafely<int>("SomeIntColumn", i));
Console.WriteLine((string)dt.GetValueSafely<string>("SomeStringColumn", i));
}
}