Manipulando ExecuteScalar () quando nenhum resultado é retornado

Eu estou usando a seguinte consulta SQL e o método ExecuteScalar() para buscar dados de um database Oracle:

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

Está me mostrando esta mensagem de erro:

System.NullReferenceException: Referência de object não definida para uma instância de um object

Este erro ocorre quando não há linha na tabela do database para userid=2 .
Como devo lidar com essa situação?

Acordo com a documentação do MSDN para DbCommand.ExecuteScalar :

Se a primeira coluna da primeira linha no conjunto de resultados não for encontrada, será retornada uma referência nula (Nothing no Visual Basic). Se o valor no database for nulo, a consulta retornará DBNull.Value.

Considere o seguinte trecho:

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

No tempo de execução (testado no ODP.NET, mas deve ser o mesmo em qualquer provedor do ADO.NET), ele se comporta assim:

  • Se a linha não existir, o resultado do command.ExecuteScalar() será nulo, que será então convertido em uma cadeia nula e atribuído a getusername .
  • Se a linha existe, mas tem NULL no nome de usuário (isso é possível no seu database?), O resultado do command.ExecuteScalar() DBNull.Value command.ExecuteScalar() é DBNull.Value , resultando em um InvalidCastException .

Em qualquer caso, o NullReferenceException não deve ser possível, portanto, seu problema provavelmente está em outro lugar.

Primeiro, você deve garantir que seu object de comando não seja nulo. Em seguida, você deve definir a propriedade CommandText do comando para sua consulta sql. Finalmente, você deve armazenar o valor de retorno em uma variável de object e verificar se é nulo antes de usá-lo:

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

Eu não tenho certeza sobre a syntax VB, mas você entendeu.

Eu só usei isso:

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

A seguinte linha:

 string getusername = command.ExecuteScalar(); 

… tentará implicitamente converter o resultado em string, como abaixo:

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

O operador de casting regular falhará se o object for nulo. Tente usar o operador, assim:

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

isso poderia ajudar .. exemplo ::

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

a partir daqui

Sempre verifique antes de ler a linha.

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

Valor SQL NULL

  • equivalente em c # é DBNull.Value
  • refere-se a algum valor em uma coluna NULLABLE
  • comparação no SQL: IF ( value IS NULL )
  • comparação em c #: if(obj == DBNull.Value)
  • representado visualmente em C # Quick-Watch como {}

Melhor prática ao ler de um leitor de dados:

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

Na minha experiência, há alguns casos em que o valor retornado pode estar faltando e, portanto, a execução falha retornando null. Um exemplo seria

 select MAX(ID) from  where 

O script acima não pode encontrar nada para encontrar um MAX. Por isso, ele falha. Nestes casos, devemos comparar o modo antigo (comparar com C # null )

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

No seu caso, o registro não existe com o userid=2 ou pode conter um valor nulo na primeira coluna, porque se nenhum valor for encontrado para o resultado da consulta usado no comando SQL, ExecuteScalar() retornará null .

Essa é a maneira mais fácil de fazer isso …

 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 } 

Como alternativa, você pode usar DataTable para verificar se há alguma linha:

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

Ligeira conjectura: se você verificar a pilha para a exceção, ela está sendo lançada, em seguida, o provedor ADO.NET para Oracle está lendo o conjunto de linhas subjacente para obter o primeiro valor.

Se não houver linha, não há valor para encontrar.

Para lidar com este caso, execute para um leitor e manipule Next() retornando false para o caso de no match.

Eu uso-o assim com o Microsoft Application Block DLL (é uma biblioteca de ajuda para operações 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 ; } 

Eu vi no VS2010 string getusername = command.ExecuteScalar(); dá erro de compilation, não é possível converter implicitamente o tipo de object em string . Então você precisa escrever string getusername = command.ExecuteScalar().ToString(); quando não há nenhum registro encontrado no database, ele fornece a referência de object de erro não definida para uma instância de um object e quando eu comento ‘.ToString ()’, não há nenhum erro. Então eu posso dizer ExecuteScalar não lançar uma exceção. Acho que anserwer dado por @Rune Grimstad está certo.

Eu tive esse problema quando o usuário se conectando ao database tinha permissions CONNECT, mas sem permissions para ler o database. No meu caso, eu não poderia nem fazer algo assim:

object userNameObj = command.ExecuteScalar()

Colocar isso em um try / catch (que você provavelmente deveria estar fazendo de qualquer maneira) era a única maneira que eu podia ver para lidar com o problema de permissão 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(); } } 

/ * Selecione algum int que não existe * /
int x = ((int) (SQL_Cmd.ExecuteScalar () ?? 0));

Eu usei isso no meu código vb para o valor de retorno de uma function:

Se obj <> Nothing então retorna obj.ToString () Else Return “” End If

Experimente este código, parece resolver o seu problema.

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

Estou usando o Oracle . Se o seu sql retorna valor numérico, que é int, você precisa usar Convert.ToInt32 (object). Aqui está o exemplo abaixo:

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

Tente isso

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