J'ai un DataTable, qui a un certain nombre de colonnes. Certaines de ces colonnes peuvent être annulées.
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 serais capable de faire quelque chose comme:
int? a = dr["A"] as int?;
Edit : Il s'avère que vous POUVEZ le faire, l'effet secondaire étant que si votre Les types de schéma ne sont pas des entiers, alors cela retournera TOUJOURS null. La réponse de Ruben d'utiliser dr.Field<int?>("A")
garantit que les incompatibilités de types n'échouent pas en silence. Ceci, bien sûr, sera détecté par des tests unitaires approfondis.
Au lieu de cela, je tape habituellement quelque chose comme:
int? a = dr["A"] != DBNull.Value ? (int)dr["A"] : 0;
C'est un tas de touches supplémentaires, mais plus important encore, il y a plus de place pour que quelqu'un bourre quelque chose avec une mauvaise frappe. Oui, un test unitaire le ramènera, mais je préfère l'arrêter complètement.
Quel est le modèle le plus propre et le moins sujet aux erreurs pour cette situation.
Le chapitre LINQ to DataSets de LINQ in Action est une bonne lecture.
Une chose que vous verrez est le Field<T>
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" );
C'est le but de la classe DataRowExtensions
dans .NET 3.5, qui fournit des Field<T>
et SetField<T>
méthodes pour aller-retour des données nullables (et non nullables) entre les types DataRow
et .NET.
int? fld = row.Field<int?>("ColumnA")
définira fld
sur null
si row["ColumnA"]
contient DBNull.Value
, à sa valeur s'il contient un entier, et lève une exception s'il contient autre chose. 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"]
à DBNull.Value
, et lui attribue la valeur fld
.
Il existe des surcharges de Field
et SetField
pour tous les types de valeurs pris en charge par DataRow
(y compris les types non nullables), vous pouvez donc utiliser le même mécanisme pour obtenir et définir quels que soient leur type de données.
int? a = (int?)dr["A"]
Les éléments suivants fonctionneraient en toute sécurité:
Snip:
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;
}
}
tilisation:
SqlDataReaderEx.TryParse(drReader, "MyColumnName", -1);
Pourquoi ne pas utiliser LINQ? Il fait la conversion pour vous.
Méthodes d'extension!
Quelque chose comme ceci:
public static class DataRowExtensions
{
public static Nullable<T> GetNullableValue<T>(this DataRow row, string columnName)
where T : struct
{
object value = row[columnName];
if (Convert.IsDBNull(value))
return null;
return (Nullable<T>)value;
}
public static T GetValue<T>(this DataRow row, string columnName)
where T : class
{
object value = row[columnName];
if (Convert.IsDBNull(value))
return null;
return (T)value;
}
}
Utilisez-le comme ceci:
int? a = dr.GetNullableValue<int>("A");
ou
string b = dr.GetValue<string>("B");