Manejando ExecuteScalar () cuando no se devuelven resultados

Estoy utilizando la siguiente consulta SQL y el método ExecuteScalar() para obtener datos de una base de datos Oracle:

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

Me está mostrando este mensaje de error:

System.NullReferenceException: referencia de objeto no establecida en una instancia de un objeto

Este error ocurre cuando no hay ninguna fila en la tabla de la base de datos para userid=2 de userid=2 .
¿Cómo debo manejar esta situación?

De acuerdo con la documentación de MSDN para DbCommand.ExecuteScalar :

Si no se encuentra la primera columna de la primera fila en el conjunto de resultados, se devuelve una referencia nula (Nothing en Visual Basic). Si el valor en la base de datos es nulo, la consulta devuelve DBNull.Value.

Considere el siguiente fragmento:

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

En tiempo de ejecución (probado en ODP.NET pero debe ser el mismo en cualquier proveedor ADO.NET), se comporta así:

  • Si la fila no existe, el resultado de command.ExecuteScalar() es nulo, que luego se convierte en una cadena nula y se asigna a getusername .
  • Si la fila existe, pero tiene NULL en el nombre de usuario (¿esto es posible incluso en su base de datos?), El resultado de command.ExecuteScalar() es DBNull.Value , lo que da como resultado una InvalidCastException .

En cualquier caso, la NullReferenceException no debería ser posible, por lo que su problema probablemente se encuentre en otra parte.

Primero debe asegurarse de que su objeto de comando no sea nulo. Luego debe establecer la propiedad CommandText del comando en su consulta SQL. Finalmente, debe almacenar el valor de retorno en una variable de objeto y comprobar si es nulo antes de usarlo:

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

No estoy seguro de la syntax de VB, pero entiendes la idea.

Acabo de usar esto:

  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 siguiente línea:

 string getusername = command.ExecuteScalar(); 

… intentará convertir implícitamente el resultado a cadena, como a continuación:

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

El operador de colada regular fallará si el objeto es nulo. Intenta usar el as-operator, así:

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

esto podría ayudar .. ejemplo ::

 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 esto aquí

Siempre revise antes de leer la fila.

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

Valor SQL NULL

  • equivalente en C # es DBNull.Value
  • se refiere a algún valor en una columna NULLABLE
  • comparación en SQL: IF ( value IS NULL )
  • comparación en C #: if(obj == DBNull.Value)
  • visualmente representado en C # Quick-Watch como {}

Las mejores prácticas al leer de un lector de datos:

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

En mi experiencia, hay algunos casos en que el valor devuelto puede faltar y, por lo tanto, la ejecución falla al devolver nulo. Un ejemplo sería

 select MAX(ID) from  where 

El script anterior no puede encontrar nada para encontrar un MAX in. Por lo tanto, falla. En estos casos, debemos comparar la forma de la moda antigua (comparar con C # null )

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

En su caso, el registro no existe con el userid=2 o puede contener un valor nulo en la primera columna, porque si no se encuentra ningún valor para el resultado de la consulta utilizado en el comando SQL, ExecuteScalar() devuelve null .

Esta es la forma más fácil de hacer esto …

 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 } 

Alternativamente, puede usar DataTable para verificar si hay alguna fila:

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

Ligera conjetura: si comprueba la stack para la excepción, se está lanzando, entonces el proveedor de ADO.NET para Oracle está leyendo el conjunto de filas subyacente para obtener el primer valor.

Si no hay fila, entonces no hay ningún valor para encontrar.

Para manejar este caso, ejecute para un lector y maneje Next() devolviendo falso para el caso de no coincidencia.

Lo uso así con Microsoft Application Block DLL (Es una biblioteca de ayuda para operaciones 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 ; } 

He visto en string getusername = command.ExecuteScalar(); da error de comstackción, no se puede convertir implícitamente el tipo de objeto a cadena . Por lo tanto, debe escribir la string getusername = command.ExecuteScalar().ToString(); cuando no se encuentra ningún registro en la base de datos, da error. La referencia del objeto no está configurada para una instancia de un objeto y cuando comento ‘.ToString ()’, no da ningún error. Entonces puedo decir que ExecuteScalar no lanza una excepción. Creo que respondido por @Rune Grimstad tiene razón.

Tuve este problema cuando el usuario que se conectaba a la base de datos tenía permisos CONNECT, pero no tenía permisos para leer desde la base de datos. En mi caso, ni siquiera podía hacer algo como esto:

object userNameObj = command.ExecuteScalar()

Poner esto en un try / catch (que probablemente deberías estar haciendo de todos modos) fue la única forma en que pude ver para manejar el problema de permiso insuficiente.

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

/ * Seleccione alguna int que no existe * /
int x = ((int) (SQL_Cmd.ExecuteScalar () ?? 0));

Utilicé esto en mi código vb para el valor de retorno de una función:

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

Pruebe este código, parece que resuelve su problema.

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

Estoy usando Oracle . Si su sql devuelve un valor numérico, que es int, necesita usar Convert.ToInt32 (object). Aquí está el ejemplo a continuación:

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

Prueba esto

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