from - leer datos datareader c#
Cómo usar datareader con valores nulos (7)
Digamos que tengo esta clase:
class myclass
{
public int Field1{ get; set; }
public int? Field2 { get; set; } //Note Field2 is nullable
}
Estoy intentando completar una lista genérica con datos provenientes de una base de datos. Como GetSqlInt32 implementa INullable, hubiera pensado que el siguiente código funcionaría. No es así Genera un error si Field2 es nulo.
List<myclass> mylist=new List<myclass>();
int Field1_Ordinal = rdr.GetOrdinal("Field1");
int Field2_Ordinal = rdr.GetOrdinal("Field2");
SqlDataReader rdr = cmd.ExecuteReader(); //Execute a stored procedure to retrieve data from the database
while (rdr.Read())
{
mylist.Add(new myclass
{
Field1 = rdr.GetSqlInt32(Field1_Ordinal).Value,
Field2 = rdr.GetSqlInt32(Field2_Ordinal).Value //Error if field2 is null
});
}
¿Alguna idea de por qué no funciona?
DbNull.Value! = Null
¿Entonces necesitas una? : expresión o un bloque if para convertir nulos de base de datos a c # nulls y vica versa.
Debe usar un método especial en el lector para detectar cuándo el valor es nulo
mylist.Add(new myclass
{
Field1 = rdr.IsDbNull(Field1_Ordinal)? 0:
rdr.GetSqlInt32(Field1_Ordinal).Value,
Field2 = rdr.IsDbNull(Field2_Ordinal)? 0: // whatever default value you wish...
rdr.GetSqlInt32(Field2_Ordinal).Value // No error now
});
Me parece que necesita una conversión como esta (utilizando un método de extensión para mayor comodidad):
public static int? ToNullableInt32(this SqlInt32 value)
{
return value.IsNull ? (int?) null : value.Value;
}
Entonces:
Field2 = rdr.GetSqlInt32(Field2_Ordinal).ToNullableInt32()
(Comente sobre otras respuestas: no es necesario incluir DbNull
en esto, ya que SqlInt32
ya puede representar valores nulos. Solo necesita detectar eso antes de usar Value
).
Creo que es porque el valor devuelto es DBNull.Value
, y no null
.
En su lugar, puede utilizar el método IsDbNull () para comprobar si el campo es nulo antes de leerlo.
Aquí hay una variación de reducción de dolor en el tema. Si alguien sabe cómo fusionar Val y Ref en una función de plantilla, puede publicarlo. Tendrás que indicar el tipo de forma explícita (compilada en C # no se puede molestar :-) pero esto:
var dd = r.Val<DateTime>(ords[4]);
var ii = r.Def<int>(ords[0]);
int nn = r.Def<int>(ords[0]);
todavía está hecho mis dedos felices :-)
public static T Def<T>(this SqlDataReader r, int ord)
{
var t = r.GetSqlValue(ord);
if (t == DBNull.Value) return default(T);
return ((INullable)t).IsNull ? default(T) : (T)t;
}
public static T? Val<T>(this SqlDataReader r, int ord) where T:struct
{
var t = r.GetSqlValue(ord);
if (t == DBNull.Value) return null;
return ((INullable)t).IsNull ? (T?)null : (T)t;
}
public static T Ref<T>(this SqlDataReader r, int ord) where T : class
{
var t = r.GetSqlValue(ord);
if (t == DBNull.Value) return null;
return ((INullable)t).IsNull ? null : (T)t;
}
Estoy intentando exportar una base de datos de Access con 39 campos, muchos de ellos con valores NULL. No pude hacer funcionar el método de extensión, así que escribí la siguiente función:
private string ChkDbStr(object inObj)
{
if (inObj == null)
{ return ""; }
else
{ return inObj.ToString(); }
}
A medida que leo cada campo que podría contener un NULL, codigo el campo leído como: ChkDbStr (DbReader.GetValue (1))
Vea esta solución que no fue escrita por mí:
employee.FirstName = sqlreader[indexFirstName] as string;
employee.Age = sqlreader[indexAge] as int? ?? default(int);
Fue propuesto originalmente aquí: