Quelle est la meilleure pratique pour gérer null int / char à partir d'une base de données SQL?
-
11-07-2019 - |
Question
J'ai une base de données qui contient le profil optionnel de l'utilisateur. Dans le profil, j'ai des chaînes, des caractères (pour M ou F) et des ints.
J'ai rencontré un problème. J'essayais de définir le sexe de l'utilisateur dans la propriété de mon objet Profile. L'application se bloquait car elle ne savait pas comment gérer une valeur null renvoyée.
J'ai essayé de convertir les données dans le type approprié
char sex = (char)dt.Rows[0]["Sex"];
Ce qui n'a pas résolu mon problème. J'ai ensuite essayé de changer les types en Nullable et Nullable et j'ai tout de même des problèmes de conversion. Ma solution actuelle que j'ai pu trouver est la suivante:
object.sex = null;
if(dt.Rows[0]["Sex"] != DBNull.Value)
object.sex = (char)dt.Rows[0]["Sex"];
object.WorkExt = null;
if(dt.Rows[0]["WorkExt"] != DBNull.Value)
object.WorkExt = (int)dt.Rows[0]["WorkExt"];
Existe-t-il un moyen plus simple ou meilleur de procéder? Ou suis-je à peu près sur la bonne voie?
La solution
rotard (utilisez Is<ColumnName>Null()
) ne fonctionne que pour les ensembles de données typés.
Pour les ensembles de données non typés, vous devez utiliser l'un des modèles du code suivant. Si ce code n'est pas définitif, faites le moi savoir et je le modifierai jusqu'à ce qu'il le soit. C’est une question extrêmement courante à laquelle il ne devrait y avoir qu’une seule bonne réponse.
using System.
using System.Data;
class Program
{
static void Main(string[] args)
{
DataTable dt = new DataTable();
dt.Columns.Add("test", typeof (char));
dt.Columns["test"].AllowDBNull = true;
DataRow dr = dt.Rows.Add();
char? test;
try
{
test = (char?)dr["test"];
}
catch (InvalidCastException)
{
Console.WriteLine("Simply casting to a nullable type doesn't work.");
}
test = dr.Field<char?>("test");
if (test == null)
{
Console.WriteLine("The Field extension method in .NET 3.5 converts System.DBNull to null.");
}
test = (dr["test"] is DBNull) ? null : (char?) dr["test"];
if (test == null)
{
Console.WriteLine("Before .NET 3.5, you have to check the type of the column's value.");
}
test = (dr["test"] == DBNull.Value) ? null : (char?) dr["test"];
if (test == null)
{
Console.WriteLine("Comparing the field's value to DBNull.Value is very marginally faster, but takes a bit more code.");
}
// now let's put the data back
try
{
dr["test"] = test;
}
catch (ArgumentException)
{
Console.WriteLine("You can't set nullable columns to null.");
}
dr.SetField("test", test);
if (dr["test"] is DBNull)
{
Console.WriteLine("Again, in .NET 3.5 extension methods make this relatively easy.");
}
dr["test"] = (object)test ?? DBNull.Value;
if (dr["test"] is DBNull)
{
Console.WriteLine("Before .NET 3.5, you can use the null coalescing operator, but note the awful cast required.");
}
Console.ReadLine();
}
}
Autres conseils
nullables ont été conçus uniquement à cette fin! utiliser 'comme personnage?' au lieu de '(char?)'
class Foo {
char? sex;
}
Foo object;
object.sex = dt.Rows[0]["Sex"] as char?;
Une discussion décente à ce sujet se trouve à Le moyen le plus efficace de rechercher DBNull, puis d’affecter une variable? .
Est-ce que dt est une table de données ADO.Net 2? Ne pouvez-vous pas faire quelque chose comme:
if(dt.Rows[0].IsSexNull()) {} else {}
? De plus, en supposant que vous contrôliez votre base de données, n’auriez-vous pas plus de sens d’utiliser un bit plutôt que une chaîne?
que diriez-vous:
internal static T CastTo<T>(object value)
{
return value != DBNull.Value ? (T)value : default(T);
}
puis utilisez-le comme:
return new EquipmentDetails(
CastTo<int>(reader["ID"]),
CastTo<int>(reader["CategoryID"]),
CastTo<string>(reader["Description"]));
etc ...
Je le ferais à peu près comme vous l'avez fait. Je voudrais écrire une fonction pour cela:
Quelque chose qui fait:
object.sex = handle(dt.Rows[0]["Sex"]);
Et dans le traitement, vous effectuez la vérification == DBNull.Value.