37 votes

Types C# DBNull et nullable - la forme la plus propre de conversion

J'ai une table de données (DataTable) qui comporte un certain nombre de colonnes. Certaines de ces colonnes sont nullables.

DataTable dt;  // Value set. 
DataRow dr;  // Value set. 

// dr["A"] is populated from T-SQL column defined as: int NULL 

Quelle est donc la forme la plus propre de conversion d'une valeur dans un DataRow en une variable nullable ?

Idéalement, je devrais pouvoir faire quelque chose comme.. :

int? a = dr["A"] as int?; 

Editar : Il s'avère que vous pouvez le faire, l'effet secondaire étant que si vos types de schéma ne sont pas des ints, alors cela va TOUJOURS retourner null. La réponse de Ruben d'utiliser dr.Field<int?>("A") garantit que les erreurs de type n'échouent pas silencieusement. Cela sera bien sûr détecté par des tests unitaires approfondis.

Au lieu de cela, je tape généralement quelque chose du genre :

int? a = dr["A"] != DBNull.Value ? (int)dr["A"] : 0; 

Cela représente beaucoup plus de frappes, mais surtout, il y a plus de place pour que quelqu'un fasse une erreur de frappe. Oui, un test unitaire le détectera, mais je préférerais l'arrêter complètement.

Quel est le modèle le plus propre et le moins sujet aux erreurs pour cette situation ?

55voto

Ruben Bartelink Points 23945

Le chapitre LINQ to DataSets de LINQ en action est une bonne lecture.

Une chose que vous verrez, c'est la Field<T> la méthode d'extension, qui est utilisée comme suit:-

int? x = dr.Field<int?>( "Field" );

Ou

int y = dr.Field<int?>( "Field" ) ?? 0;

Ou

var z = dr.Field<int?>( "Field" );

12voto

Robert Rossney Points 43767

C'est le but de l' DataRowExtensions classe .NET 3.5, qui fournit statique Field<T> et SetField<T> méthodes en aller-retour nullable (et non nullable) des données entre l' DataRow et .Types de réseau.

int? fld = row.Field<int?>("ColumnA")

mettra fld de null si row["ColumnA"] contient DBNull.Value, de sa valeur si elle contient un nombre entier, et de lever une exception si elle contient quelque chose d'autre. Et sur le chemin du retour,

row.SetField("ColumnA", fld);

fait la même chose en sens inverse: si fld contient null, il définit row["ColumnA"] de DBNull.Value, et sinon, il définit à la valeur de fld.

Il existe des surcharges d' Field et SetField pour tous les types de valeur qu' DataRow prend en charge (y compris les types nullables), de sorte que vous pouvez utiliser le même mécanisme pour l'obtention et définition des champs quel que soit leur type de données.

4voto

bniwredyc Points 4682
int? a = (int?)dr["A"]

1voto

stepanian Points 2867

Pourquoi ne pas utiliser LINQ ? Il fait la conversion pour vous.

1voto

KMån Points 7972

Suivre fonctionnerait en toute sécurité:

Couper:

 public static class SqlDataReaderEx
{
    public static int TryParse(SqlDataReader drReader, string strColumn, int nDefault)
    {
        int nOrdinal = drReader.GetOrdinal(strColumn);
        if (!drReader.IsDbNull(nOrdinal))
            return drReader.GetInt32(nOrdinal);
        else
            return nDefault;
    }
}
 

Usage:

 SqlDataReaderEx.TryParse(drReader, "MyColumnName", -1);
 

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X