当没有结果返回时处理ExecuteScalar()

我正在使用以下SQL查询和ExecuteScalar()方法从Oracle数据库中获取数据:

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

它向我显示了这个错误消息:

System.NullReferenceException:未将对象引用设置为对象的实例

userid=2的数据库表中没有行时,会发生此错误

我应该如何处理这种情况?

根据DbCommand.ExecuteScalar的MSDN文档 :

如果结果集中第一行的第一列未find,则返回null引用(在Visual Basic中为Nothing)。 如果数据库中的值为空,则查询返回DBNull.Value。

考虑下面的代码片段:

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

在运行时(在ODP.NET下testing,但在任何ADO.NET提供者下应该是一样的),它的行为如下:

  • 如果该行不存在,则command.ExecuteScalar()的结果为空,然后将其转换为空string并分配给getusername
  • 如果行存在,但在用户名中有NULL(这在数据库中甚至可能?), command.ExecuteScalar()的结果是DBNull.Value ,导致InvalidCastException

无论如何, NullReferenceException应该是不可能的,所以你的问题可能在别处。

首先你应该确保你的命令对象不为空。 然后你应该设置命令的CommandText属性到你的SQL查询。 最后,你应该把返回值存储在一个对象variables中,并在使用它之前检查它是否为null:

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

我不确定VB的语法,但你明白了。

我只是用这个:

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

以下行:

 string getusername = command.ExecuteScalar(); 

…将尝试隐式地将结果转换为string,如下所示:

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

如果对象为null,常规的转换运算符将失败。 尝试使用as-operator,如下所示:

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

这可以帮助..例如::

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

从这里

在阅读行之前,一定要检查一下。

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

在你的情况下,logging不存在于userid=2或者它可能在第一列中包含空值,因为如果在SQL命令中使用的查询结果没有find值, ExecuteScalar()返回null

这是做这个最简单的方法…

 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 } 

或者,您可以使用DataTable来检查是否有任何行:

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

轻微的猜想:如果您检查堆栈的exception,它正在被抛出然后ADO.NET提供程序的Oracle正在读取底层的行集以获得第一个值。

如果没有行,那么没有价值可以find。

为了处理这种情况,为读者执行并处理Next() ,如果不匹配,则返回false。

我使用它与Microsoft应用程序块DLL(它是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 ; } 

我在VS2010中看到string getusername = command.ExecuteScalar(); 给出编译错误, 不能隐式地将types对象转换为string 。 所以你需要写string getusername = command.ExecuteScalar().ToString(); 当在数据库中没有findlogging时,它给出错误的对象引用没有设置为一个对象的实例,当我注释“.ToString()”,它不会给出任何错误。 所以我可以说ExecuteScalar不会抛出exception。 我认为@Rune Grimstad提供的是正确的。

当连接到数据库的用户具有CONNECT权限但没有从数据库中读取权限时,我遇到了这个问题。 就我而言,我什至不能做这样的事情:

object userNameObj = command.ExecuteScalar()

把它放在一个try / catch中(你应该可以这样做),这是我看到处理权限不足问题的唯一方法。

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

/ *select一些不存在的int * /
int x =((int)(SQL_Cmd.ExecuteScalar()?? 0));

我在我的VB代码中使用这个函数的返回值:

如果obj <> Nothing Then返回obj.ToString()否则返回“”End If

试试这个代码,它似乎解决了你的问题。

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

我正在使用Oracle 。 如果你的sql返回数值,即int,你需要使用Convert.ToInt32(object)。 这里是下面的例子:

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

尝试这个

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