2009-09-01 6 views
7

Dire que j'ai cette classe:Comment utiliser datareader avec des valeurs nulles

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

Je suis en train de remplir une liste générique avec des données provenant d'une base de données. Comme GetSqlInt32 implémente INullable, j'aurais pensé que le code ci-dessous fonctionnerait. Ce n'est pas le cas. Il génère une erreur si Field2 est null.

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 
    }); 
} 

Des idées pour lesquelles cela ne fonctionne pas?

Répondre

24

Il me semble que vous avez besoin d'une conversion comme celui-ci (en utilisant une méthode d'extension pour plus de commodité):

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

Puis:

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

(Donnez votre avis sur d'autres réponses: il n'y a pas besoin d'apporter DbNull dans ce, comme SqlInt32 peut déjà représenter des valeurs nulles. Vous avez juste besoin de le détecter avant d'utiliser Value.)

+0

Merci pour cela, mais pourquoi pas quelque chose comme ça sans utiliser une méthode d'extension: Champ2 = (rdr.IsDBNull (Field2_Ordinal)? (Int?) NULL: rdr.GetSqlInt32 (Field2_Ordinal) .Value) – Anthony

+0

@Anthony: Simplicité, fondamentalement . Quelle version pensez-vous est plus facile à lire? :) (Oui, cela signifie avoir la méthode d'extension supplémentaire, mais vous n'avez besoin que de * une fois *, mais de nombreux champs int nullables.) –

+0

Vous pouvez également créer une méthode d'extension sur DataReader appelée GetNullableInt32 ou quelque chose comme ça, bien sûr . –

0

DBNull.Value! = Null

Vous devez donc disposer d'un? : expression ou un bloc if pour convertir les valeurs nulles de la base de données en valeurs nulles C# et vica versa.

1

I pense que est parce que la valeur retournée est DBNull.Value, et non null. A la place, vous pouvez utiliser la méthode IsDbNull() pour vérifier si le champ est nul avant de le lire.

+1

La valeur renvoyée est un SqlInt32, pas un DBNull.Value. –

1

Vous devez utiliser une méthode spéciale sur le lecteur pour détecter lorsque la valeur est nulle

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

dans mon cas: Champ2 = rdr.IsDbNull (Field2_Ordinal)? (int?) null: rdr.GetSqlInt32 (Field2_Ordinal) .Valeur Merci pour votre réponse. – Anthony

4

Voici une variation de réduction de la douleur sur le thème. Si quelqu'un sait comment fusionner Val et Ref en un seul modèle, la fonction est libre de publier. Vous devrez indiquer le type explicitement (C# compilé ne peut pas être dérangé :-) mais ceci:

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

est encore maked mes doigts heureux :-)

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

Merci d'avoir posté ceci. –

1

Je suis en train de exporter une base de données Access avec 39 champs - beaucoup avec des valeurs NULL. Je ne pouvais pas la méthode d'extension de travail j'ai donc écrit la fonction suivante:

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

Comme je l'ai lu chaque champ qui peut contenir un NULL, je code le champ lu comme: ChkDbStr (DbReader.GetValue (1))

6

Vérifiez cette solution qui n'a pas été écrit par moi:

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

Il a été proposé ici:

SQL Data Reader - handling Null column values

Questions connexes