Getting null reference exception calling stored proc - c#

I run code that produces a datatable. From this datatable, I gleen the State & CRID. I use these pieces of information to run code to get the PRID. Problem is, every time I run this, I get a Null Reference Exception. I've tried declaring int PRID = 0 before running the code; however, I then end up with 0 as my answer every time. I've executed the code in SQLServer 2008 using the same parameters, and I get the correct result.
I am unable to determine why this code is not running correctly.
public int GetPRID(int RRID, string State, int PCID)
{
try
{
SQLCON = new SqlConnection(connectionString);
SQLCON.Open();
SQLCmd = new SqlCommand("spGetPRID", SQLCON);
SQLCmd.CommandType = CommandType.StoredProcedure;
SQLCmd.Parameters.Add("#RRID", SqlDbType.Int).Value = RRID;
SQLCmd.Parameters.Add("#State", SqlDbType.VarChar).Value = State;
SQLCmd.Parameters.Add("#PCID", SqlDbType.Int).Value = PCID;
int PRID = (Int32)SQLCmd.ExecuteScalar();
return PRID;
}
catch(Exception ex)
{
HttpContext.Current.Response.Redirect("~/ErrorRedirect.aspx?" + ex.Message, false);
return 0;
}
finally
{
SQLCON.Close();
}
}

This line is problematic here
int PRID = (Int32)SQLCmd.ExecuteScalar();
of course I can't know the result of your stored procedure, but ExecuteScalar could return NULL and if this is the case the cast to Int32 will fail with the error null reference exception
MSDN says
Returns the first column of the first row in the result set, or a null
reference (Nothing in Visual Basic) if the result set is empty
So the correct approach if there is a possibility to get a null as return value is
object result = SQLCmd.ExecuteScalar();
if(result != null)
PRID = Convert.ToInt32(result);

From memory SQLCmd.ExecuteScalar() will return null if no value is returned, which will give you a null reference exception. If a value is returned but the value is a database null it will return BDNull.value, which will also fail because it can't be cast to an int32.

I found the issue. It wasn't in my C# code - it was within the SQL itself. I was declaring #PRID as int, and asking it to return #PRID.
Once I removed this, it worked fine. Thank you all for your contributions.

Related

How to determine if ExecuteReader returned a result set or not

I'm working on a concept to retrieve the Schema from an executed stored procedure. The goal is to loop through multiple stored procedures to generate a data dictionary.
I have a CLR Assembly that's retrieving the data. For performance reasons, the stored procs have parameters automatically generated to produce no rows so the expectation is to get an empty result set that I can retrieve the schema from. The issue I'm running in to is that it's possible for a stored procedure to be passed into the function that does not have a result set. I need a way to handle and identify these stored procedures.
Here is the function:
public static void Return_ColumnData(SqlString query)
{
DataTable schema = null;
SqlConnection connection = new SqlConnection("context connection=true");
string sQuery = query.ToString();
using (SqlCommand command = new SqlCommand(sQuery, connection))
{
try
{
connection.Open();
SqlDataReader reader = command.ExecuteReader();
schema = reader.GetSchemaTable();
reader.Close();
string insertQuery = "INSERT INTO #tmpColData (ColumnName, Length, Precision, Scale, DataType) SELECT #ColumnName, #Length, #Precision, #Scale, #DataType";
foreach (DataRow myField in schema.Rows)
{
using (SqlCommand insertCommand = new SqlCommand(insertQuery, connection))
{
insertCommand.Parameters.Add("#ColumnName", SqlDbType.NVarChar, 100).Value = myField[0].ToString();
insertCommand.Parameters.Add("#Length", SqlDbType.Int).Value = Convert.ToInt32(myField[2]);
insertCommand.Parameters.Add("#Precision", SqlDbType.Int).Value = Convert.ToInt32(myField[3]);
insertCommand.Parameters.Add("#Scale", SqlDbType.Int).Value = Convert.ToInt32(myField[4]);
insertCommand.Parameters.Add("#DataType", SqlDbType.NVarChar, 100).Value = myField[24].ToString();
insertCommand.ExecuteNonQuery();
}
}
connection.Close();
}
catch (SqlException exception)
{
SqlContext.Pipe.Send(exception.Errors[0].Message);
}
}
}
If I don't handle it it will throw this error from the stored procedure that calls the assembly (Return_ColumnData):
Msg 50000, Level 16, State 1, Procedure dbo.Procedure2DataDict, Line 236 [Batch Start Line 0]
6522 A .NET Framework error occurred during execution of user-defined routine or aggregate "Return_ColumnData":
System.NullReferenceException: Object reference not set to an instance of an object.
System.NullReferenceException:
at Procedure2DataDict.Return_ColumnData(SqlString query)
I tried adding a reader.HasRows to determine whether or not there was a result set but it will return false if there is no result set and if there is 0 rows which does not work for me.
if (reader.HasRows)
{
schema = reader.GetSchemaTable();
} else
{
SqlContext.Pipe.Send("Failed to get schema. No rows output.");
reader.Close();
connection.Close();
return;
}
I have to assume something to handle no result set with ExecuteReader() exists. I know there is a difference between ExecuteReader() and ExecuteNonQuery() but since the function will be run for an iteration of multiple procedures, I don't know beforehand if the proc will return a result set or not.
Any help is appreciated.
You should use FieldCount.
From Remarks:
Executing a query that, by its nature, does not return rows (such as a DELETE query), sets FieldCount to 0.
So I believe the answer was staring me in the face in the form of the error I was receiving.
The error message is a NullReferenceException so I've decided instead of checking HasRows to just ensure the result of GetSchemaData() != null.
if (reader.GetSchemaTable() != null)
{
schema = reader.GetSchemaTable();
} else
{
SqlContext.Pipe.Send("Failed to get schema. No rows output.");
reader.Close();
connection.Close();
return;
}
I've tested for my cases and it is working as expected.
I understand there are probably multiple ways to handle this and people can still contribute with an explanation of their method.
Thanks!

ExecuteScalar return null

I am using below SQL Server function to check is userName and password entered by user through C# windows forms are correct or not as show below too but at first I am getting error at line cmd.ExecuteScalar(); saying
{"Object reference not set to an instance of an object."}
after trying to handle that error I get the error on
return result.ToString();
How I am getting null value if the SQL Server function not returning null value it return 1 or -1 if there is no match within the database?
Even so I searched and tried to handle the null value returned from the cmd.ExecuteScalar(); as you can see my tries but none of the gose successfully
please if anyone can help me ...thanks
you probably want to do something like this :
public string userLogin()
{
string connStr = ConfigurationManager.ConnectionStrings["SRJDconnstr"].ToString();
string cmdStr = #"SELECT dbo.USER_LOGIN(#USER_NAME, #PWD)";
using (SqlConnection conn = new SqlConnection(connStr))
using (SqlCommand cmd = new SqlCommand(cmdStr, conn))
{
conn.Open();
cmd.Parameters.AddWithValue("#USER_NAME", TB_USER_NAME.Text);
cmd.Parameters.AddWithValue("#PWD", TB_PWD.Text);
var result = cmd.ExecuteScalar();
return result.ToString();
}
}
cmd.ExecuteScalar() will return the first column of the first row in the result set.
Your SQL Server function code ends with RETURN #vResult which is the RETURN value.
Try and replace RETURN #vResult with SELECT #vResult.

How execute a stored procedure from the web method?

I want to execute a stored procedure inside a Web Method. It is a select statement in the stored procedure. I tried with the following code. However, the result not successful. The result should return 1 but it is always returning -1. Does anyone have any idea? Please help.
Here is the web service .asmx code:
public class retrieveLoan : System.Web.Services.WebService
{
string constring = "Data Source=DIT-NB1260382;Initial Catalog=Experiment;Integrated Security=True";
SqlConnection myConn;
[WebMethod(Description="Simple Example")]
public int GetResult(int id, int age)
{
Int32 numberofRecords = 0;
System.Data.DataSet workDS = new System.Data.DataSet();
SqlCommand objCommand = default(SqlCommand);
//Create a command object
objCommand = new SqlCommand();
//prepare the command for retreiving
objCommand.CommandType = System.Data.CommandType.StoredProcedure;
objCommand.CommandText = "myprocedure2";
//open the connection
myConn = new SqlConnection(constring);
myConn.Open();
objCommand.Connection = myConn;
try
{
numberofRecords = (Int32)objCommand.ExecuteScalar();
return numberofRecords;
}
catch (Exception)
{
return -1;
}
finally
{
myConn.Close();
}
}
}
and my store procedure:
ALTER PROCEDURE [dbo].[myprocedure2]
(
#puserid int,
#page int
)
AS
BEGIN
select * from userdet where userid = #puserid and age = #page
END
I believe that executing this stored procedure without parameters would return an exception.
First of all, for you to see the Exception, in the catch declaration, you should try and declare the Exception explicitly, like this:
try
{
numberofRecords = (Int32)objCommand.ExecuteScalar();
return numberofRecords;
}
catch (Exception ex)
{
//here you can enter into debug mode and see the exception "ex"
return -1;
}
finally
{
myConn.Close();
}
When you see the exception, you can quickly solve the problem.
Next, you should add the parameters as NULL into your stored procedure (so they can accept null values), OR, if you do not, you must add these parameter in C# code, and send them some values.
Also, i would like to point the fact that if you want to retrieve a COUNT, you should modify your stored procedure as following:
ALTER PROCEDURE [dbo].[myprocedure2] ( #puserid int, #page int )
AS
BEGIN
select COUNT(userid) from userdet where userid = #puserid and age = #page
END
Hope this solves your issues here.
You're not providing a lot of info, so hard to answer, but here's a way forward:
Change catch (Exception) into catch (Exception ex), then see what that exception contains, either by returning it, or by analyzing it in debug mode.
If you publish your project in debug mode, you can connect to it and debug it using Tools > Attach to Process and connect to the process called w3wp.exe (if there are more than one of them, look for the one with the correct version of .Net under the Type-column).
Your query is "select * from userdet". What ExecuteScalar() does is pick the first cell value. Now you are type casting this to int. if your first cell value is a string type or some other type. you will definitely receive a error. And that will return -1. Please define the column name in your select query or count like this "select count(*) from userdet". Check ur query.

What would you do here? Return a null or throw an exception (framework design guides)

I'm developing a C# .NET Framework 4.0 library.
I have this code:
public static byte GetBatchStatus(string connString)
{
if (string.IsNullOrEmpty(connString))
throw new ArgumentNullException("connString");
byte status;
using (System.Data.SqlClient.SqlConnection conn = new System.Data.SqlClient.SqlConnection(connString))
{
conn.Open();
SqlCommand cmd = new SqlCommand();
cmd.CommandText = GetBatchStatusValueSQL;
cmd.CommandType = CommandType.Text;
cmd.Connection = conn;
object o = cmd.ExecuteScalar();
// Throws an ArgumentNullException if o is null.
if (o == null)
throw new ArgumentNullException("o");
status = Convert.ToByte(o);
}
return status;
}
cmd.ExecuteScalar(); could return a null, but Convert.ToByte(o); returns 0.
If cmd.ExecuteScalar(); returns null its an error, because the value I'm looking for must be on database. If that value is not on database is an error.
What would you do here? Return a null or throw an exception?
You are pretty much answering your own question:
because the value I'm looking for must be on database. If that value is not on database is an error.
If your program doesn't function without that value you should throw an exception, if not you can return null and make the user of the library decide what to do next.
I think if you want to do something if cmd.ExecuteScalar() returns null then you should return a null. But as you said
the value I'm looking for must be on database. If that value is not on database is an error.
then you should throw an exception type of InvalidOperationException rather than ArgumentNullException.
If that value is not on database is an error.
An error in terms of "my belief system about the state of the system has been violated" or "the input must be invalid somehow"? It sounds like it's more the former - so I'd throw an exception. It sounds like the caller can't reasonably continue in this case. If they can, that's a different matter.
You might want to use InvalidOperationException, or perhaps create your own exception (InvalidDatabaseStateException for example) given that it's not really the state of this object which is invalid.
According to here http://msdn.microsoft.com/en-us/library/ms229009(v=vs.110).aspx and here http://msdn.microsoft.com/en-us/library/ms229030(v=vs.110).aspx exceptions are very expensive and should be used with care.
I surely would use return Convert.ToByte(o) and test it on the calling function.

Using the SQL Command object, how can you check to see if the result set is empty?

Using the ExecuteScalar method in the SQL Command object, how can you check to see if the result set is empty? I am using ASP.net, C#, and MS SQL 2008. Right now when I run the following code the Response.Write returns a 0 when the resultset is empty. But I would like to differentiate between 0 and empty resultsets because there are actual 0 values in my database.
Here is the current code behind:
cmd = new SqlCommand("usp_test", cn);
cmd.CommandType = CommandType.StoredProcedure;
cn.Open();
TestOuput = Convert.ToInt32(cmd.ExecuteScalar());
cn.Close();
Response.Write(TestOutput);
Thank you.
Check out the definition of ExecuteScalar. It returns an Object, which will have a null reference if the result set is empty.
The reason you are seeing zero is that Convert.ToInt32 returns a zero when given null. You need to check the return value from ExecuteScalar before you convert it to an int.
DbCommand.ExecuteScalar() returns the first column of the first row, or null if the result is empty. Your problem is caused by Convert.ToInt32() because it returns 0 for null.
You have to check the value returned by ExecuteScalar() for null and only call Convert.ToInt32() if it is not null.
Object result = command.ExecuteScalar();
if (result != null)
{
Int32 value = Convert.ToInt32(result);
}
else
{
// Handle the empty result set case
}
As you can see in here you can check if the result is null :
Return Value Type: System.Object
The first column of the first row in
the result set, or a null reference
(Nothing in Visual Basic) if the
result set is empty.
Execute scalar will return the first column of the first row in the result set. If there are no results it should return null.
My guess is that your stored procedure is returning a count and not the dataset, which is why you are seeing a 0.
ExecuteScalar returns null if the result set is empty (as #fallen888, et al. have said). The reason you are seeing zero is that Convert.ToInt32 returns a zero when given null. You need to check the return value from ExecuteScalar before you convert it to an int.
cmd = new SqlCommand("usp_test", cn);
cmd.CommandType = CommandType.StoredProcedure;
cn.Open();
Object outPut=cmd.ExecuteScalar();
if(outPut!=null)
TestOuput = Convert.ToInt32(outPut);
else
//Return Empty Set
cn.Close();
Response.Write(TestOutput);

Categories

Resources