2009-09-01 24 views
7

Decir que tengo esta clase:Cómo usar datareader con valores nulos

class myclass 
{ 
    public int Field1{ get; set; } 
    public int? Field2 { get; set; } //Note Field2 is nullable 
} 

Estoy intentando rellenar una lista genérica con los datos procedentes 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?

Respuesta

24

Me parece que necesita una conversión así (usando un método de extensión por conveniencia):

public static int? ToNullableInt32(this SqlInt32 value) 
{ 
    return value.IsNull ? (int?) null : value.Value; 
} 

continuación:

Field2 = rdr.GetSqlInt32(Field2_Ordinal).ToNullableInt32() 

(Comentarios sobre otras respuestas: no hay necesidad de llevar DbNull en esto, ya que SqlInt32 ya puede representar valores nulos. Solo necesita detectar eso antes de usar Value.)

+0

Gracias por esto, pero por qué no algo como esto sin necesidad de utilizar un método de extensión: Campo2 = (rdr.IsDBNull (Field2_Ordinal) (int) null:?? Rdr.GetSqlInt32 (Field2_Ordinal) .Value) – Anthony

+0

@Anthony: Simplicidad, básicamente . ¿Qué versión crees que es más fácil de leer? :) (Sí, significa que tienes el método de extensión adicional, pero solo necesitas ese * una vez *, sin importar cuántos campos NULL incluye). –

+0

También puedes crear un método de extensión en DataReader llamado GetNullableInt32 o algo así, por supuesto . –

0

DBNull.Value! = Null

por lo que necesita ya sea una? : expresión o un bloque if para convertir nulos de base de datos a C# nulls y vica versa.

1

Yo creo es por culpa del 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.

+1

El valor devuelto es un SqlInt32, no un DBNull.Value. –

1

usted tiene que utilizar un método especial en el lector para detectar cuando 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 
}); 
+0

en mi caso: Field2 = rdr.IsDbNull (Field2_Ordinal)? (int?) null: rdr.GetSqlInt32 (Field2_Ordinal) .Value Gracias por su respuesta. – Anthony

4

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á que indicar el tipo de forma explícita (C# compilado no puede ser molestado :-) pero esto:

var dd = r.Val<DateTime>(ords[4]); 
var ii = r.Def<int>(ords[0]); 
int nn = r.Def<int>(ords[0]); 

sigue maked 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; 
} 
+0

Gracias por publicar esto. –

1

Estoy intentando Exporte una base de datos de Access con 39 campos, muchos de ellos con valores NULL. No pude conseguir el método de extensión de trabajo así que escribí la siguiente función:

private string ChkDbStr(object inObj) 
{ 
    if (inObj == null) 
    { return ""; } 
    else 
    { return inObj.ToString(); } 
} 

Al leer cada campo que puede contener un valor NULL, cifro el campo leer como: ChkDbStr (DbReader.GetValue (1))

6

salida esta solución que no fue escrito por mí:

employee.FirstName = sqlreader[indexFirstName] as string; 
employee.Age = sqlreader[indexAge] as int? ?? default(int); 

originalmente se propone aquí:

SQL Data Reader - handling Null column values

Cuestiones relacionadas