Manipuler ExecuteScalar () si aucun résultat n’est renvoyé

J’utilise la requête SQL suivante et la méthode ExecuteScalar() pour extraire des données d’une firebase database Oracle:

 sql = "select username from usermst where userid=2" ssortingng getusername = command.ExecuteScalar(); 

Il me montre ce message d’erreur:

System.NullReferenceException: référence d’object non définie sur une instance d’un object

Cette erreur se produit lorsqu’il n’y a pas de ligne dans la table de firebase database pour userid=2 .
Comment dois-je gérer cette situation?

Selon la documentation MSDN pour DbCommand.ExecuteScalar :

Si la première colonne de la première ligne du jeu de résultats est introuvable, une référence null (Nothing en Visual Basic) est renvoyée. Si la valeur de la firebase database est NULL, la requête renvoie DBNull.Value.

Considérez l’extrait suivant:

 using (var conn = new OracleConnection(...)) { conn.Open(); var command = conn.CreateCommand(); command.CommandText = "select username from usermst where userid=2"; ssortingng getusername = (ssortingng)command.ExecuteScalar(); } 

Au moment de l’exécution (testé sous ODP.NET mais devrait être le même sous n’importe quel fournisseur ADO.NET), il se comporte comme ceci:

  • Si la ligne n’existe pas, le résultat de command.ExecuteScalar() est null, qui est ensuite converti en chaîne getusername et affecté à getusername .
  • Si la ligne existe, mais a NULL dans le nom d’utilisateur (est-ce même possible dans votre firebase database?), Le résultat de command.ExecuteScalar() est DBNull.Value , entraînant une InvalidCastException .

Dans tous les cas, l’ NullReferenceException ne devrait pas être possible, votre problème est donc probablement ailleurs.

Vous devez d’abord vous assurer que votre object de commande n’est pas nul. Ensuite, vous devez définir la propriété CommandText de la commande sur votre requête SQL. Enfin, vous devez stocker la valeur de retour dans une variable d’object et vérifier si elle est nulle avant de l’utiliser:

 command = new OracleCommand(connection) command.CommandText = sql object userNameObj = command.ExecuteScalar() if (userNameObj != null) ssortingng getUserName = userNameObj.ToSsortingng() ... 

Je ne suis pas sûr de la syntaxe VB, mais vous avez l’idée.

Je viens d’utiliser ceci:

  int? ReadTerminalID() { int? terminalID = null; using (FbConnection conn = connManager.CreateFbConnection()) { conn.Open(); FbCommand fbCommand = conn.CreateCommand(); fbCommand.CommandText = "SPSYNCGETIDTERMINAL"; fbCommand.CommandType = CommandType.StoredProcedure; object result = fbCommand.ExecuteScalar(); // ExecuteScalar fails on null if (result.GetType() != typeof(DBNull)) { terminalID = (int?)result; } } return terminalID; } 

La ligne suivante:

 ssortingng getusername = command.ExecuteScalar(); 

… essaiera de convertir implicitement le résultat en chaîne, comme ci-dessous:

 ssortingng getusername = (ssortingng)command.ExecuteScalar(); 

L’opérateur de casting régulier échouera si l’object est nul. Essayez d’utiliser l’opérateur as, comme ceci:

 ssortingng getusername = command.ExecuteScalar() as ssortingng; 
 sql = "select username from usermst where userid=2" var _getusername = command.ExecuteScalar(); if(_getusername != DBNull.Value) { getusername = _getusername.ToSsortingng(); } 

cela pourrait aider .. exemple ::

 using System; using System.Data; using System.Data.SqlClient; class ExecuteScalar { public static void Main() { SqlConnection mySqlConnection =new SqlConnection("server=(local)\\SQLEXPRESS;database=MyDatabase;Integrated Security=SSPI;"); SqlCommand mySqlCommand = mySqlConnection.CreateCommand(); mySqlCommand.CommandText ="SELECT COUNT(*) FROM Employee"; mySqlConnection.Open(); int returnValue = (int) mySqlCommand.ExecuteScalar(); Console.WriteLine("mySqlCommand.ExecuteScalar() = " + returnValue); mySqlConnection.Close(); } } 

de ceci ici

Toujours vérifier avant de lire la ligne.

 if (SqlCommand.ExecuteScalar() == null) { } 

Valeur SQL NULL

  • l’équivalent en C # est DBNull.Value
  • il fait référence à une valeur dans une colonne NULLABLE
  • comparaison en SQL: IF ( value IS NULL )
  • comparaison en C #: if(obj == DBNull.Value)
  • représenté visuellement dans C-Quick-Watch en tant que {}

Meilleures pratiques lors de la lecture d’un lecteur de données:

 var reader = cmd.ExecuteReader(); ... var result = (reader[i] == DBNull.Value ? "" : reader[i].ToSsortingng()); 

Dans mon expérience, il y a quelques cas où la valeur renvoyée peut être manquante et par conséquent, l’exécution échoue en renvoyant null. Un exemple serait

 select MAX(ID) from  where 

Le script ci-dessus ne trouve rien pour trouver un MAX. Donc, il échoue. Dans ces cas, il faut comparer l’ancienne façon (comparé à C # null )

 var obj = cmd.ExecuteScalar(); var result = (obj == null ? -1 : Convert.ToInt32(obj)); 

Dans votre cas, l’enregistrement n’existe pas avec l’ userid=2 ou il peut contenir une valeur nulle dans la première colonne, car si aucune valeur n’est trouvée pour le résultat de la requête utilisé dans la commande SQL, ExecuteScalar() renvoie null .

C’est le moyen le plus simple de le faire …

 sql = "select username from usermst where userid=2" object getusername = command.ExecuteScalar(); if (getusername!=null) { //do whatever with the value here //use getusername.toSsortingng() to get the value from the query } 

Vous pouvez également utiliser DataTable pour vérifier s’il y a des lignes:

 SqlCommand cmd = new SqlCommand("select username from usermst where userid=2", conn); SqlDataAdapter adp = new SqlDataAdapter(cmd); DataTable dt = new DataTable(); adp.Fill(dt); ssortingng getusername = ""; // assuming userid is unique if (dt.Rows.Count > 0) getusername = dt.Rows[0]["username"].ToSsortingng(); 

Légère conjecture: si vous vérifiez la stack pour l’exception, elle est lancée, alors le fournisseur ADO.NET pour Oracle lit l’ensemble de lignes sous-jacent pour obtenir la première valeur.

S’il n’y a pas de ligne, il n’y a pas de valeur à trouver.

Pour gérer ce cas, exécutez pour un lecteur et gérez Next() retournant false pour la casse sans correspondance.

Je l’utilise comme ça avec Microsoft Application Block DLL (c’est une bibliothèque d’aide pour les opérations DAL)

 public ssortingng getCopay(ssortingng PatientID) { ssortingng sqlStr = "select ISNULL(Copay,'') Copay from Test where patient_id=" + PatientID ; ssortingng strCopay = (ssortingng)SqlHelper.ExecuteScalar(CommonCS.ConnectionSsortingng, CommandType.Text, sqlStr); if (Ssortingng.IsNullOrEmpty(strCopay)) return ""; else return strCopay ; } 

J’ai vu dans VS2010 ssortingng getusername = command.ExecuteScalar(); donne une erreur de compilation, impossible de convertir implicitement un object de type en chaîne . Vous devez donc écrire ssortingng getusername = command.ExecuteScalar().ToSsortingng(); lorsqu’il n’y a pas d’enregistrement trouvé dans la firebase database, il donne une référence d’object non définie à une instance d’un object et lorsque je commente “.ToSsortingng ()”, cela ne donne aucune erreur. Je peux donc dire que ExecuteScalar ne lance pas d’exception. Je pense que anserwer donné par @Rune Grimstad a raison.

J’ai eu ce problème lorsque l’utilisateur se connectant à la firebase database avait des permissions CONNECT, mais pas d’permissions à lire à partir de la firebase database. Dans mon cas, je ne pouvais même pas faire quelque chose comme ceci:

object userNameObj = command.ExecuteScalar()

Mettre cela dans un try / catch (ce que vous devriez probablement faire de toute façon) était la seule façon dont je pouvais voir gérer le problème de l’autorisation insuffisante.

 private static ssortingng GetUserNameById(ssortingng sId, ssortingng connStr) { System.Data.SqlClient.SqlConnection conn = new System.Data.SqlClient.SqlConnection(connStr); System.Data.SqlClient.SqlCommand command; try { // To be Assigned with Return value from DB object getusername; command = new System.Data.SqlClient.SqlCommand(); command.CommandText = "Select userName from [User] where userid = @userid"; command.Parameters.AddWithValue("@userid", sId); command.CommandType = CommandType.Text; conn.Open(); command.Connection = conn; //Execute getusername = command.ExecuteScalar(); //check for null due to non existent value in db and return default empty ssortingng ssortingng UserName = getusername == null ? ssortingng.Empty : getusername.ToSsortingng(); return UserName; } catch (Exception ex) { throw new Exception("Could not get username", ex); } finally { conn.Close(); } } 

/ * Sélectionnez un int qui n’existe pas * /
int x = ((int) (SQL_Cmd.ExecuteScalar () ?? 0));

Je l’ai utilisé dans mon code vb pour la valeur de retour d’une fonction:

Si obj <> Nothing Retourne alors obj.ToString () Else Return “” End If

Essayez ce code, il semble résoudre votre problème.

Dim MaxID As Integer = Convert.ToInt32(IIf(IsDBNull(cmd.ExecuteScalar()), 1, cmd.ExecuteScalar()) )

J’utilise Oracle . Si votre SQL renvoie une valeur numérique, qui est int, vous devez utiliser Convert.ToInt32 (object). Voici l’exemple ci-dessous:

 public int GetUsersCount(int userId) { using (var conn = new OracleConnection(...)){ conn.Open(); using(var command = conn.CreateCommand()){ command.CommandText = "select count(*) from users where userid = :userId"; command.AddParameter(":userId", userId); var rowCount = command.ExecuteScalar(); return rowCount == null ? 0 : Convert.ToInt32(rowCount); } } } 

Essaye ça

 sql = "select username from usermst where userid=2" ssortingng getusername = Convert.ToSsortingng(command.ExecuteScalar());