74

I am using the following SQL query and the ExecuteScalar() method to fetch data from an Oracle database:

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

It is showing me this error message:

System.NullReferenceException: Object reference not set to an instance of an object

This error occurs when there is no row in the database table for userid=2.
How should I handle this situation?

Hakan Fıstık
  • 16,800
  • 14
  • 110
  • 131
Hemant Kothiyal
  • 4,092
  • 19
  • 61
  • 80
  • What ADO.NET provider are you using? ODP.NET? – Branko Dimitrijevic Oct 31 '11 at 00:54
  • 2
    the `OracleCommand` `ExecuteScalar` returns an object for the result. It's not strongly typed because the SQL statement is arbitrary, so the type isn't known until it's parsed (which is by the DB engine, not by the .NET runtime). The object returned can be `null`. You are assuming it is a string, and it may well be, and a lot of types can be implicitly converted to such, but it's a very dangerous assumption to make - that object can be of **any** type. As with any other object reference that you don't explicitly trust, first you should make sure it's not `null`. – Ed B Jun 22 '15 at 16:10
  • A correct answer would be nice on this one. – Eric Bishard Oct 16 '15 at 20:52

23 Answers23

61

According to MSDN documentation for DbCommand.ExecuteScalar:

If the first column of the first row in the result set is not found, a null reference (Nothing in Visual Basic) is returned. If the value in the database is null, the query returns DBNull.Value.

Consider the following snippet:

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

At run-time (tested under ODP.NET but should be the same under any ADO.NET provider), it behaves like this:

  • If the row does not exist, the result of command.ExecuteScalar() is null, which is then casted to a null string and assigned to getusername.
  • If the row exists, but has NULL in username (is this even possible in your DB?), the result of command.ExecuteScalar() is DBNull.Value, resulting in an InvalidCastException.

In any case, the NullReferenceException should not be possible, so your problem probably lies elsewhere.

Liam
  • 27,717
  • 28
  • 128
  • 190
Branko Dimitrijevic
  • 50,809
  • 10
  • 93
  • 167
55

First you should ensure that your command object is not null. Then you should set the CommandText property of the command to your sql query. Finally you should store the return value in an object variable and check if it is null before using it:

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

I'm not sure about the VB syntax but you get the idea.

Hakan Fıstık
  • 16,800
  • 14
  • 110
  • 131
Rune Grimstad
  • 35,612
  • 10
  • 61
  • 76
  • 1
    That will probably not help a lot since it is the call to `ExecuteScalar` that throws the exception. – Fredrik Mörk Jan 04 '10 at 11:47
  • Hmm... That might be the problem, but the poster describes the problem as "no row exists ... for id = 2" - hence I assume that the database connection is setup correctly. Updating my answer anyhow. – Rune Grimstad Jan 04 '10 at 11:51
  • Yess it work, But i am not getting why should we avoid using executescalar() – Hemant Kothiyal Jan 04 '10 at 11:58
  • 6
    You shouldn't avoid using ExecuteScalar. It is the recommended method to use when you only want a single return value from a query. The problem is that it returns an Object, not a value of the type you want. The reason is that the database can contain a null value in the column and the query may not return a value at all. That is why you store the value in an object type variable that you cast to the apropriate type. – Rune Grimstad Jan 04 '10 at 12:10
32

I just used this:

    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;
    }
Fanda
  • 3,760
  • 5
  • 37
  • 56
  • I tried your code and I get thrown an exception in the if condition statement, so I changed it simple to: if (result != null) and it worked. Still +1 for your answer. Thanks. – WhySoSerious Jan 09 '14 at 10:15
  • even with null value checking goes inside if condition. DBNull is Working! result.GetType() != typeof(DBNull) – Nishantha Sep 26 '14 at 09:42
16

The following line:

string getusername = command.ExecuteScalar();

... will try to implicitly convert the result to string, like below:

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

The regular casting operator will fail if the object is null. Try using the as-operator, like this:

string getusername = command.ExecuteScalar() as string;
Raktim Biswas
  • 4,011
  • 5
  • 27
  • 32
Tommy Carlier
  • 7,951
  • 3
  • 26
  • 43
  • Thanks, It works, but can you compare your answer with others(Rune Grimstad,Fredrik Mörk ) I am confused now which one is best practice – Hemant Kothiyal Jan 04 '10 at 12:04
  • 1
    If you only want to get 1 value, ExecuteScalar is a good method to use. You just have to be careful how you handle the object you get. Using the as-operator will not throw a NullReferenceException when casting null to a string. – Tommy Carlier Jan 04 '10 at 12:08
  • 1
    The: `object o = null; string s = (string)o;` does **not** throw an exception, so I'm wondering if the exception was really because of `ExecuteScalar()` returning a `null`? @HemantKothiyal did you actually test this in run-time and confirmed that replacing a cast with `as` stops the exception? And did you get the expected result in `getusername`? – Branko Dimitrijevic Oct 31 '11 at 00:37
  • 1
    @HemantKothiyal BTW, `string getusername = command.ExecuteScalar();` does not compile - *error CS0266: Cannot implicitly convert type 'object' to 'string'. An explicit conversion exists (are you missing a cast?)* Could you post the actual code you have used? – Branko Dimitrijevic Oct 31 '11 at 00:53
  • @HemantKothiyal check the msdn about "as" operator ( https://msdn.microsoft.com/zh-tw/library/cscsdfbt.aspx ) The as operator is like a cast operation.However, if the conversion isn't possible, as returns null instead of raising an exception.Consider the following example: – Hsu Wei Cheng Feb 16 '16 at 06:44
  • In this specific case the `as` operator is useful because it will return `null` when `ExecuteScalar` returns a `DBNull` object (when the first column contains NULL) and return the string or null (when the row is not found) otherwise. The last line is correct, but the explanation is flawed. – Olivier Jacot-Descombes Dec 02 '20 at 12:54
10
sql = "select username from usermst where userid=2"
var _getusername = command.ExecuteScalar();
if(_getusername != DBNull.Value)
{
    getusername = _getusername.ToString();
}  
9

Check out the example below:

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

from this here

ag93
  • 343
  • 4
  • 17
jjj
  • 605
  • 1
  • 9
  • 26
7

SQL NULL value

  • equivalent in C# is DBNull.Value
  • if a NULLABLE column has no value, this is what is returned
  • comparison in SQL: IF ( value IS NULL )
  • comparison in C#: if (obj == DBNull.Value)
  • visually represented in C# Quick-Watch as {}

Best practice when reading from a data reader:

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

In my experience, there are some cases the returned value can be missing and thus execution fails by returning null. An example would be

select MAX(ID) from <table name> where <impossible condition>

The above script cannot find anything to find a MAX in. So it fails. In these such cases we must compare the old fashion way (compare with C# null)

var obj = cmd.ExecuteScalar();
var result = (obj == null ? -1 : Convert.ToInt32(obj));
andrensairr
  • 452
  • 2
  • 5
  • 17
Bizhan
  • 16,157
  • 9
  • 63
  • 101
5

Always have a check before reading row.

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

}
pravprab
  • 2,301
  • 3
  • 26
  • 43
Sagar
  • 115
  • 1
  • 2
  • 7
5

If you either want the string or an empty string in case something is null, without anything can break:

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;
}
radbyx
  • 9,352
  • 21
  • 84
  • 127
2

This is the easiest way to do this...

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
}
some_yahoo
  • 39
  • 1
1

In your case either the record doesn't exist with the userid=2 or it may contain a null value in first column, because if no value is found for the query result used in SQL command, ExecuteScalar() returns null.

Bart Friederichs
  • 33,050
  • 15
  • 95
  • 195
MAX
  • 46
  • 1
1

Alternatively, you can use DataTable to check if there's any row:

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();
alkk
  • 331
  • 5
  • 11
1
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();
        }

    }
SMA
  • 74
  • 2
0

I Use it Like This with Microsoft Application Block DLL (Its a help library for DAL operations)

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 ;
}
panky sharma
  • 2,029
  • 28
  • 45
0

Slight conjecture: if you check the stack for the exception, it is being thrown then the ADO.NET provider for Oracle is reading the underlying rowset to get the first value.

If there is no row, then there is no value to find.

To handle this case execute for a reader and handle Next() returning false for the case of no match.

Richard
  • 106,783
  • 21
  • 203
  • 265
0

I have seen in VS2010 string getusername = command.ExecuteScalar(); gives compilation error, Cannot implicitly convert type object to string. So you need to write string getusername = command.ExecuteScalar().ToString(); when there is no record found in database it gives error Object reference not set to an instance of an object and when I comment '.ToString()', it is not give any error. So I can say ExecuteScalar not throw an exception. I think anserwer given by @Rune Grimstad is right.

minu
  • 157
  • 1
  • 3
  • 13
0

I had this issue when the user connecting to the database had CONNECT permissions, but no permissions to read from the database. In my case, I could not even do something like this:

object userNameObj = command.ExecuteScalar()

Putting this in a try/catch (which you should probably be doing anyway) was the only way I could see to handle the insufficient permission issue.

Freefall
  • 73
  • 5
0
object objUserName;
objUserName = command.ExecuteScalar();

if (objUserName == null)  //if record not found ExecuteScalar returns null
{
    return "";
}
else
{
    if (objUserName == DBNull.Value)  //if record found but value in record field is null
    {
        return "";
    }
    else
    {
        string getusername = objUserName.ToString();
        return getusername; 
    }
}
DerpyNerd
  • 4,743
  • 7
  • 41
  • 92
TonyB
  • 1
  • While code-only answers might solve the problem at hand (even if it is eleven years old), it will not help future readers to understand what the problem is and why it can be solved this way. So please do also add an explanation (not just comments in your code-only answer). – Tobias Brösamle Mar 17 '21 at 10:35
-1

/* Select some int which does not exist */
int x = ((int)(SQL_Cmd.ExecuteScalar() ?? 0));

-1

I used this in my vb code for the return value of a function:

If obj <> Nothing Then Return obj.ToString() Else Return "" End If

BJM
  • 1
-1

Try this code, it appears to solve your problem.

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

Lilith Daemon
  • 1,473
  • 1
  • 19
  • 37
-1

I'm using Oracle. If your sql returns numeric value, which is int, you need to use Convert.ToInt32(object). Here is the example below:

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);
        }
    }
}
Mahesh
  • 309
  • 4
  • 8
-2

Try this

sql = "select username from usermst where userid=2"

string getusername = Convert.ToString(command.ExecuteScalar());
j0k
  • 22,600
  • 28
  • 79
  • 90
zam
  • 1