当没有结果返回时处理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());