La manipulación de un DateTime DBNull
Pregunta
he visto muchas, muchas versiones de este sobre SO, pero ninguno de ellos parecen bastante trabajo para mis necesidades.
Mi datos proceden de una base de datos de proveedores que permite nula para los campos de fecha y hora. En primer lugar me tire de mis datos en un DataTable.
using (SqlCommand cmd = new SqlCommand(sb.ToString(), conn))
using (SqlDataAdapter da = new SqlDataAdapter(cmd))
{
da.Fill(dt);
}
Estoy convirtiendo un DataTable a un List <> para su procesamiento.
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")
}
Entonces, ¿cómo puedo comprobar por DBNull en este caso? Traté de escribir un método.
public DateTime CheckDBNull(object dateTime)
{
if (dateTime == DBNull.Value)
return DateTime.MinValue;
else
return (DateTime)dateTime;
}
Solución
Una opción posible es almacenarlo como una fecha y hora anulable con la sintaxis DateTime?
Aquí hay un enlace a la MSDN sobre el uso de tipos anulables
Otros consejos
System.Convert.IsDBNull(value);
o si tiene un SqlDataReader
reader.IsDBNull(ordinal);
Y hacer que sus propiedades DateTime
ser anulable (DateTime?
) y el conjunto null
en caso de DBNull
. Field<T>()
lo hará automáticamente.
aquí es un ejemplo de un código que utilizo para leer datetimes
im seguro de que se podría escribir mejor, pero corre bien, para mí
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;
}
He encontrado que la mejor manera de manejar esto es para echar el campo como su tipo de datos utilizando el "como" palabra clave. Esto funciona muy bien para los campos de base de datos que puede ser nulo, y es agradable y sencilla.
Aquí hay más detalles sobre esto: directa de fundición vs 'como' operador
Ejemplo:
IDataRecord record = FromSomeSqlQuerySource;
string nullableString;
DateTime? nullableDateTime;
nullableString = record["StringFromRecord"] as string;
nullableDateTime = record["DateTimeFromRecord"] as DateTime?;
Se debe utilizar para comparar DataRow["ColumnName"] is DBNull
DateTime nula.
por ejemplo:.
if(studentDataRow["JoinDate"] is DBNull) { // Do something here }
Me escribió un método de extensión genérica que utilizo en todos mis proyectos:
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;
}
Ejemplo de uso:
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));
}
}