[C#] Caster les données d'une DataRow

Bonjour à tous.

Je viens de me mettre au C#, et j’ai un petit problème en ce qui concerne les DataRow :

J’ai récupéré une DataTable via SQL server contenant les données d’une table Products.

J’ai fait une classe Product, et vu que la table contient facile une cinquantaine de champs, au lieu d’en déclarer autant dans ma classe je préfère garder directement la DataRow concernant un produit, plus 3 champs qui sont plus souvent utilisés : l’ID du product (un int), son nom et son code (des string). En plus, c’est plus pratique pour les updates.

Voici le constructeur de ma classe Product :

[code]  public Product(DataRow dataRow)
 {

 row = dataRow; // row est un champ de la classe

 productID = (int)row["ProductID"];

 productCode = (string)row["ProductCode"];
 productName = (string)row["ProductName"];

 }[/code]

Comme vous pouvez le constater, pour l’ID, le code et le nom je fais des cast, et ca passe nickel, si je fais un writeline de chaque, il me les affiche bien.

Maintenant, j’ai mis chaque champ de la DataRow en propriété, et c’est là que ca se corse :

 public int FamilyID  {  get  {    return (int)row["ProductID"];  }  }

En effet, ce genre d’accès passe à la compilation, mais pas à l’exécution, où j’ai droit à une belle InvalidCastException, quel que soit le type du champ à renvoyer (int, float, booleen ou string).

J’ai essayé de remplacer les types primitifs par des objets (int => Int32, float => Double …etc…), ce qui donne pour l’exemple précédent :

 public Int32 FamilyID  {  get  {    Int32 i = (Int32) row["FamilyID"];    return i;  }  }

Quand je fais comme ça, ça foire pour tous les champs en Int32, le reste ça passe à peu près à part quelques uns qui me lévent toujours la même exception… :stuck_out_tongue:

La seule solution que j’ai trouvé pour remédier à ça est de parser les champs numériques à partir du toString() de chaque valeur dans la DataRow mais quand même, c’est sale comme façon de faire :

 public intFamilyID  {  get  {    int i = int.Parse(row["FamilyID"].toString());    return i;  }  }

Voilà, je me suis pris la tête la dessus toute la matinée, et j’aimerais bien savoir pourquoi le cast marche sans problème dans le constructeur, et pas dans les propriétés. Quelqu’un peut-il m’éclairer là-dessus ?

Je précise que je programme sous visual studio .NET 2003

Merci.

Je pense pas que ce soit sale en utilisant Int.Parse(), en tout cas c’est ce que je fais depuis 2 mois que je me suis mis a c# :stuck_out_tongue:

T’a essaye sans le toString() mais en utilisant le Int.Parse() quand meme ?

Un moyen rapide pour connaitre le type à utiliser pour le transtypage : mets un breakpoint sur ta ligne de code, et appelle la propriété dans la fenêtre commande ou passe la dans une fenetre espion (?row[“FamilyID”]). Tu devrais obtenir le type natif de la variable, t’indiquant donc comment transtyper correctement ta colonne. A mon avis, c’est juste une question de taille (Int16 au lieu de Int32 par ex.)

Pour les types en int, j’ai essayé Int16/32/64, ça a rien changé.

Sinon j’ai testé le coup de l’espion, et ça foire sur des champs qui peuvent être à null, mais ce qui est bizarre c’est que c’est que sur certains, et pas tous.

En fait j’ai l’impression que le prog bloque quand il rencontre un champ numérique qui est null dans la base…

Tu as essayé un test sur DBNull ?

Oui j’ai testé, et là où ça bloque le type est bien DBNULL.

Je sais pas si DBNULL est vraiment un truc null, ou si c’est juste une classe/structure qui le représente, parce que si je fait un getType() sur l’objet fautif obtenu dans ma DataRow, j’ai pas de NullPointerException, ça me renvoie bien DBNull.

Donc même si le champ de la base est null, l’objet correspondant dans la DataRow n’a pas l’air de l’être, et donc je devrais pouvoir le caster non ?

J’ai faux ?

Alors le type DBNull est un type bien spécial et il s’il est là, c’est justement pour gérer des cas ou un simple null ne suffirait pas.

En gros, pour bien faire, tu es obligé de tester si ta valeur est à DBNull avant de tenter de la transtyper en quoi que ce soit… Simplement parce qu’un Int32 ne peut valoir null (type valeur), donc comment te dire que la colonne de type int qui accepte les null est à null justement ? Ben en utilisant un autre type, un peu spécial, qui permet de le savoir.

Si tu cherches du côté de DBNull ou SqlDataReader.IsDBNull sur MSDN, tu trouveras comment il te faut écrire correctement ton programme pour gérer les cas de colonnes à null (notamment en utilisant les SqlTypes qui implémentent les valeurs DBNull directement)

OK merci pour le conseil.

Je vais fureter de ce côté là.

Oui le probleme c’est que DBNull ne peut etre casté en rien d’autre. Avant les nullable types de 2.0 il faut tester si ce que tu recupere dans ta DataRow est un DBNull et faire ce que tu veux faire dans ce cas la (si c’est pour renvoyer 0 pour un int je vois pas trop l’interet de l’avoir comme nullable dans la DB mais bon…).