web-dev-qa-db-fra.com

Gestion de ExecuteScalar () quand aucun résultat n'est renvoyé

J'utilise la requête SQL suivante et la méthode ExecuteScalar() pour récupérer les données d'une base de données Oracle:

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

Il me montre ce message d'erreur:

System.NullReferenceException: la référence à un objet n'est pas définie sur une instance d'objet

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

55
Hemant Kothiyal

Selon 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 (rien dans Visual Basic) est renvoyée. Si la valeur de la base de données 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";
    string getusername = (string)command.ExecuteScalar();
}

Au moment de l'exécution (testé sous ODP.NET mais devrait être identique sous n'importe quel fournisseur ADO.NET), il se comporte comme suit:

  • Si la ligne n'existe pas, le résultat de command.ExecuteScalar() est null, lequel est ensuite converti en une chaîne nulle et affecté à getusername.
  • Si la ligne existe, mais que son nom d'utilisateur est NULL (est-ce même possible dans votre base de données?), Le résultat de command.ExecuteScalar() est DBNull.Value, Ce qui donne un InvalidCastException.

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

51

Tout d'abord, vous devez vous assurer que votre objet 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 devriez stocker la valeur de retour dans une variable d'objet 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)
  string getUserName = userNameObj.ToString()
 ...

Je ne suis pas sûr de la syntaxe VB mais vous voyez l'idée.

48
Rune Grimstad

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;
    }
22
Fanda

La ligne suivante:

string getusername = command.ExecuteScalar();

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

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

L'opérateur de casting normal échouera si l'objet est null. Essayez d'utiliser l'opérateur as, comme ceci:

string getusername = command.ExecuteScalar() as string;
8
Tommy Carlier
sql = "select username from usermst where userid=2"
var _getusername = command.ExecuteScalar();
if(_getusername != DBNull.Value)
{
    getusername = _getusername.ToString();
}  
7

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();
  }
}

à partir de ceci ici

6
jjj

SQL [~ # ~] null [~ # ~] valeur

  • l'équivalent en C # est DBNull.Value
  • si une colonne NULLABLE n'a pas de valeur, c'est ce qui est retourné
  • comparaison en SQL: IF ( value IS NULL )
  • comparaison en C #: if (obj == DBNull.Value)
  • représenté visuellement dans C # Quick-Watch en tant que {}

Meilleure pratique lors de la lecture d'un lecteur de données:

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

D'après mon expérience, dans certains cas, la valeur renvoyée peut être manquante. Par conséquent, l'exécution échoue en renvoyant la valeur null. Un exemple serait

select MAX(ID) from <table name> where <impossible condition>

Le script ci-dessus ne trouve rien pour trouver un MAX. Il échoue donc. Dans de tels cas, nous devons comparer l'ancienne méthode (comparer avec C # null)

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

Toujours avoir une vérification avant de lire la ligne.

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

}
3
Sagar

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.toString() to get the value from the query
}
2
some_yahoo

Vous pouvez également utiliser DataTable pour vérifier s'il y a une ligne:

SqlCommand cmd = new SqlCommand("select username from usermst where userid=2", conn);
SqlDataAdapter adp = new SqlDataAdapter(cmd);
DataTable dt = new DataTable();
adp.Fill(dt);
string getusername = "";
// assuming userid is unique
if (dt.Rows.Count > 0)
    getusername = dt.Rows[0]["username"].ToString();
1
alkk
private static string GetUserNameById(string sId, string 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 string
            string UserName = getusername == null ? string.Empty : getusername.ToString();

            return UserName;


        }
        catch (Exception ex)
        {

            throw new Exception("Could not get username", ex);
        }
        finally
        {
            conn.Close();
        }

    }
1
SMA

Dans votre cas, l'enregistrement n'existe pas avec le 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() retourne null.

1
MAX

J'ai eu ce problème lorsque l'utilisateur se connectant à la base de données avait les autorisations CONNECT, mais aucune autorisation de lire à partir de la base de données. Dans mon cas, je ne pouvais même pas faire quelque chose comme ça:

object userNameObj = command.ExecuteScalar()

Mettre cela dans un essai/attraper (ce que vous devriez probablement faire de toute façon) était la seule façon pour moi de gérer le problème de l’insuffisance des permissions.

0
Freefall

Si vous voulez soit le string ou un empty string au cas où quelque chose est nul, sans quoi rien ne peut casser:

using (var cmd = new OdbcCommand(cmdText, connection))
{
    var result = string.Empty;
    var scalar = cmd.ExecuteScalar();
    if (scalar != DBNull.Value) // Case where the DB value is null
    {
        result = Convert.ToString(scalar); // Case where the query doesn't return any rows. 
        // Note: Convert.ToString() returns an empty string if the object is null. 
        //       It doesn't break, like scalar.ToString() would have.
    }
    return result;
}
0
radbyx

J'ai vu dans VS2010 string getusername = command.ExecuteScalar(); donne une erreur de compilation, Impossible implicitement de convertir un objet de type en chaîne. Donc, vous devez écrire string getusername = command.ExecuteScalar().ToString(); quand il n'y a pas d'enregistrement trouvé dans la base de données, cela donne une erreur La référence d'objet n'est pas définie sur une instance d'objet et quand je commente '.ToString ()' , ce n'est pas donner une erreur. Je peux donc dire que ExecuteScalar ne jette pas une exception. Je pense que la réponse donnée par @Rune Grimstad est juste.

0
minu

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

public string getCopay(string PatientID)
{
       string sqlStr = "select ISNULL(Copay,'') Copay from Test where patient_id=" + PatientID ;
        string strCopay = (string)SqlHelper.ExecuteScalar(CommonCS.ConnectionString, CommandType.Text, sqlStr);
                if (String.IsNullOrEmpty(strCopay))
                    return "";
                else
                    return strCopay ;
}
0
panky sharma

Légère conjecture: si vous vérifiez la pile à la recherche d'une exception, le fournisseur ADO.NET pour Oracle lit le jeu 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 manipulez Next() retournant false pour le cas sans correspondance.

0
Richard