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?
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:
command.ExecuteScalar()
est null, lequel est ensuite converti en une chaîne nulle et affecté à getusername
.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.
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.
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:
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;
sql = "select username from usermst where userid=2"
var _getusername = command.ExecuteScalar();
if(_getusername != DBNull.Value)
{
getusername = _getusername.ToString();
}
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
SQL [~ # ~] null [~ # ~] valeur
IF ( value IS NULL )
if (obj == DBNull.Value)
{}
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));
Toujours avoir une vérification avant de lire la ligne.
if (SqlCommand.ExecuteScalar() == 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.toString() to get the value from the query
}
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();
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();
}
}
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
.
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.
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;
}
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.
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 ;
}
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.