117 votes

Impossible de convertir l'objet de type 'System.DBNull' en type 'System.String'.

J'ai obtenu l'erreur ci-dessus dans mon application. Voici le code original

public string GetCustomerNumber(Guid id)
{
     string accountNumber = 
          (string)DBSqlHelperFactory.ExecuteScalar(connectionStringSplendidmyApp, 
                          CommandType.StoredProcedure, 
                          "GetCustomerNumber", 
                          new SqlParameter("@id", id));
     return accountNumber.ToString();
 }

Je l'ai remplacé par

public string GetCustomerNumber(Guid id)
{
   object accountNumber =  
          (object)DBSqlHelperFactory.ExecuteScalar(connectionStringSplendidCRM, 
                                CommandType.StoredProcedure, 
                                "spx_GetCustomerNumber", 
                                new SqlParameter("@id", id));
    if (accountNumber is System.DBNull)
    {
       return string.Empty;
    }
    else
    {
       return accountNumber.ToString();
    }
}

Y a-t-il un meilleur moyen de contourner ce problème ?

2 votes

Vous devriez vraiment regarder la réponse de @rein, cela vous fera gagner beaucoup de temps à long terme

211voto

rein Points 15639

Avec une simple fonction générique, vous pouvez rendre cela très facile. Il suffit de faire ceci :

return ConvertFromDBVal<string>(accountNumber);

en utilisant la fonction :

public static T ConvertFromDBVal<T>(object obj)
{
    if (obj == null || obj == DBNull.Value)
    {
        return default(T); // returns the default value for the type
    }
    else
    {
        return (T)obj;
    }
}

1 votes

Oui, une fonction comme celle-ci est la seule solution pratique. Tout type de logique en ligne échouera après que vous l'ayez copié et collé un millier de fois :-)

3 votes

Cela ne fonctionnera pas si vous essayez de convertir 1 en bool (Convert.ToBoolean(1) fonctionne bien).

0 votes

@roman : nous voudrions donc avoir une vérification supplémentaire (avant la vérification de null) qui vérifie le type booléen...

97voto

User Points 13983

Un formulaire plus court peut être utilisé :

return (accountNumber == DBNull.Value) ? string.Empty : accountNumber.ToString()

EDIT : Je n'ai pas prêté attention à ExecuteScalar. Il retourne vraiment null si le champ est absent du résultat de retour. Donc utilisez-le à la place :

return (accountNumber == null) ? string.Empty : accountNumber.ToString()

3 votes

Cela ne marchera pas - le "accountNumber" est no une valeur de base de données, mais une instance d'un vieil "objet" .NET ordinaire - vous devez vérifier la valeur "nulle" normale. La valeur DBNull.Value fonctionnerait pour un SqlDataReader ou un SqlParameter - mais pas pour cet objet ici.

0 votes

Vous avez raison, j'ai commencé à optimiser la partie vérification des conditions, je n'ai pas regardé la ligne avant. Mea culpa.

0 votes

Il y a une coquille dans votre message que je ne peux pas vraiment éditer car l'édition nécessite 6 caractères à modifier. Quelqu'un peut-il remplacer accountNumber.TosString() par accountNumber.ToString() ?

17voto

Joe Points 60749

ExecuteScalar retournera

  • null s'il n'y a pas d'ensemble de résultats
  • sinon la première colonne de la première ligne du jeu de résultats, qui peut être DBNull.

Si vous savez que la première colonne du jeu de résultats est une chaîne de caractères, alors, pour couvrir toutes les bases, vous devez vérifier à la fois les null et les DBNull. Quelque chose comme :

object accountNumber = ...ExecuteScalar(...);
return (accountNumber == null) ? String.Empty : accountNumber.ToString();

Le code ci-dessus repose sur le fait que DBNull.ToString renvoie une chaîne vide.

Si accountNumber était d'un autre type (par exemple un nombre entier), il faudrait être plus explicite :

object accountNumber = ...ExecuteScalar(...);
return (accountNumber == null || Convert.IsDBNull(accountNumber) ?     
         (int) accountNumber : 0;

Si vous êtes sûr que votre jeu de résultats contiendra toujours au moins une ligne (par exemple, SELECT COUNT(*)...), vous pouvez ignorer la vérification de null.

Dans votre cas, le message d'erreur "Unable to cast object of type 'System.DBNull' to type 'System.String`" indique que la première colonne de votre jeu de résultats est une valeur DBNUll. Ceci est dû au cast en string sur la première ligne :

string accountNumber = (string) ... ExecuteScalar(...);

Le commentaire de Marc_s selon lequel il n'est pas nécessaire de vérifier la présence de DBNull.Value est faux.

0 votes

Mon jeu de résultats ne renvoie pas toujours une ligne.

7voto

Nathan Koop Points 9115

Vous pouvez utiliser l'opérateur de coalescence de nullité de C#

return accountNumber ?? string.Empty;

0 votes

-1 : Cela ne compilera pas : la méthode renvoie une chaîne et accountNumber est un objet.

2 votes

Return Cmd.ExecuteScalar().ToString() ? ? String.Empty ;

0 votes

Return Cmd.ExecuteScalar().ToString() a fait le travail pour moi.

3voto

Russel Yang Points 748

Il existe un autre moyen de contourner ce problème. En utilisant la fonction sql ISNULL(votre champ, ""), vous pouvez retourner une chaîne vide si la valeur de retour est nulle.

Vous avez alors votre code propre comme version originale.

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