Ado.net ExecuteScalar() returning null - c#

I am executing a stored procedure in c# (through vs2008) using ado.net with an ExecuteScalar command. The stored proc returns the pkey of the new record entered, but ExecuteScalar is returning null. I look in the database and a record has indeed been added. I could use an output parameter to get the value, but then I won't know why this didn't work.
When I execute the sp in ssms, the pkey is returned.
What am I doing wrong?
Here is the C# code:
public int SaveNewPerson(EPerson ePerson)
{
int newPersonPkey;
SqlConnection cn = new SqlConnection(cnn.PersonData);
using (cn)
{
try
{
SqlCommand cmd = new SqlCommand();
cmd.Connection = cn;
cmd.CommandType = CommandType.StoredProcedure;
cmd.CommandText = "People.dbo.AddNewPerson";
cmd.Parameters.Add("#LastName", SqlDbType.VarChar, 150).Value = ePerson.LastName;
cmd.Parameters.Add("#FirstName", SqlDbType.VarChar, 150).Value = ePerson.FirstName;
cn.Open();
object result = cmd.ExecuteScalar();
newPersonPkey = int.Parse(result.ToString());
cn.Close();
}
catch (Exception e)
{
// call error method
throw new Exception(e.Message + " save new Person error ");
}
}
return newPersonPkey;
}
And this is the sp:
PROCEDURE [dbo].[AddNewPerson]
#FirstName varchar(50)
,#LastName varchar(50)
AS
BEGIN
SET NOCOUNT ON;
INSERT INTO [People].[dbo].[Persons]
(
[FirstName]
,[LastName]
)
VALUES
(
#FirstName
,#LastName
)
declare #persons_PKey int
set #persons_PKey = ##IDENTITY
return #persons_PKey
end

The ExecuteScalar method returns the first field of the first record of the result, but as your query doesn't produce a result, it will return null.
You can either select the value instead of returning it from the stored procedure, or add a parameter with the direction set to ParameterDirection.ReturnValue to catch what the stored procedure returns.

Try changing the Stored Procedure to use a Select Statement to return the identity instead of using a return like this:
SELECT CAST(scope_identity() AS int)
Thus changing your procedure to:
PROCEDURE [dbo].[AddNewPerson]
#FirstName varchar(50)
,#LastName varchar(50)
AS
BEGIN
SET NOCOUNT ON;
INSERT INTO [People].[dbo].[Persons]
(
[FirstName]
,[LastName]
)
VALUES
(
#FirstName
,#LastName
)
SELECT CAST(scope_identity() AS int)
end
From the documentation of the ExecuteScalar() on MSDN it says that it will return the first column of the first row in the result set or null otherwise if the result set is empty.

Related

Why i can not handle the store procedure return value is c#?

I'm new in c#,and want to write simple application work with sql server store procedure,in the sql server write this store procedure:
USE [mammutRecruitment]
ALTER PROCEDURE [dbo].[FirstStep]
#Name nvarchar(max),#Family nvarchar(max),#FatherName nvarchar(max),#BirthCertificate bigint,#PlaceOfBirth nvarchar(max),#BirthDate datetime,
#NationalCode bigint,#Religion nvarchar(max),#faith nvarchar(max),#Nationality nvarchar(max),#BloodGroup nvarchar(max)
AS
BEGIN
DECLARE #MYID bigint
insert into [dbo].[UserMainSpecifications] values(#Name,#Family,#FatherName,#BirthCertificate,#PlaceOfBirth,1,#BirthDate,#NationalCode,
#Religion,#faith,#Nationality,#BloodGroup,12,'123','123',1,2015-1-1,'12','123','1234',1)
select #MYID=[UserID] from [mammutRecruitment].[dbo].[UserMainSpecifications]
where [NationalCode]=#NationalCode
select #MYID as myID
END
and in c# write this code for call that:
using (SqlConnection con = new SqlConnection("Data Source=.;Initial Catalog=mammutRecruitment;Integrated Security=True"))
{
using (SqlCommand cmd = new SqlCommand("FirstStep", con))
{
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.Add("#Name", SqlDbType.NVarChar).Value = m.Name;
cmd.Parameters.Add("#Family", SqlDbType.NVarChar).Value = m.Family;
cmd.Parameters.Add("#FatherName", SqlDbType.NVarChar).Value = m.FatherName;
cmd.Parameters.Add("#BirthCertificate", SqlDbType.BigInt).Value =Convert.ToInt64(m.BirthCertificate);
cmd.Parameters.Add("#PlaceOfBirth", SqlDbType.NVarChar).Value = m.PlaceOfBirth;
cmd.Parameters.Add("#BirthDate", SqlDbType.DateTime).Value =Convert.ToDateTime(dt.ToString());
cmd.Parameters.Add("#NationalCode", SqlDbType.BigInt).Value =Convert.ToInt64(m.NationalCode);
cmd.Parameters.Add("#Religion", SqlDbType.NVarChar).Value = m.Religion;
cmd.Parameters.Add("#faith", SqlDbType.NVarChar).Value = m.faith;
cmd.Parameters.Add("#Nationality", SqlDbType.NVarChar).Value = m.Nationality;
cmd.Parameters.Add("#BloodGroup", SqlDbType.NVarChar).Value = m.BloodGroup;
SqlParameter retval = cmd.Parameters.Add("#myID", SqlDbType.BigInt);
retval.Direction = ParameterDirection.ReturnValue;
con.Open();
cmd.ExecuteNonQuery();
var retunvalue = cmd.Parameters["#myID"].Value;
but in the this line i get zero value always:
var retunvalue = cmd.Parameters["#myID"].Value;
What happen?How can i solve that problem?thanks.
This line:
cmd.ExecuteNonQuery();
Is executing your query and not returning a value.
You could start by looking into using this instead:
cmd.ExecuteReader();
Or if you want the value of the first field of the first row, you could use this:
var returnValue = cmd.ExecuteScalar();
Which will give you an object that you can then convert or cast into the appropriate type for your method.
SqlCommand.ExecuteNonQuery Method ()
Executes a Transact-SQL statement against the connection and returns
the number of rows affected.
SqlCommand.ExecuteScalar Method ()
Executes the query, and returns the first column of the first row in
the result set returned by the query. Additional columns or rows are
ignored.
I believe you want the second method
You need to include #myID as an output parameter in your stored procedure definition:
ALTER PROCEDURE [dbo].[FirstStep]
#Name nvarchar(max),#Family nvarchar(max),#FatherName nvarchar(max),#BirthCertificate bigint,#PlaceOfBirth nvarchar(max),#BirthDate datetime,
#NationalCode bigint,#Religion nvarchar(max),#faith nvarchar(max),#Nationality nvarchar(max),#BloodGroup nvarchar(max)
, #myID bigint output
AS
And then remove the line
DECLARE #MYID bigint
You also need to add the parameter to cmd in your c# code:
cmd.Parameters.Add(retval);
you need define #MYID as output parameter.
USE [mammutRecruitment]
ALTER PROCEDURE [dbo].[FirstStep]
#MYID bigint output,#Name nvarchar(max),#Family nvarchar(max),#FatherName nvarchar(max),#BirthCertificate bigint,#PlaceOfBirth nvarchar(max),#BirthDate datetime,
#NationalCode bigint,#Religion nvarchar(max),#faith nvarchar(max),#Nationality nvarchar(max),#BloodGroup nvarchar(max)
AS
BEGIN
insert into [dbo].[UserMainSpecifications] values(#Name,#Family,#FatherName,#BirthCertificate,#PlaceOfBirth,1,#BirthDate,#NationalCode,
#Religion,#faith,#Nationality,#BloodGroup,12,'123','123',1,2015-1-1,'12','123','1234',1)
select #MYID = SCOPE_IDENTITY()
END
and add your command
SqlParameter pOut = new SqlParameter("#MYID", SqlDbType.BigInt);
pOut.Direction = ParameterDirection.Output;
cmd.Parameters.Add(pOut);
You can read the value now
cmd.ExecuteNonQuery();
long newId = (long)pOut.Value;
Actually, you need change that statement:
retval.Direction = ParameterDirection.ReturnValue;
to
retval.Direction = ParameterDirection.Output
because ExecuteNonQuery return:
Executes a Transact-SQL statement against the connection and returns the number of rows affected.
Although the ExecuteNonQuery returns no rows, any output parameters or return values mapped to parameters are populated with data.
End include your parameter to procedure definition:
#myID BIGINT OUTPUT
USE [mammutRecruitment]
ALTER PROCEDURE [dbo].[Firststep] #Name NVARCHAR(max),
#Family NVARCHAR(max),
#FatherName NVARCHAR(max),
#BirthCertificate BIGINT,
#PlaceOfBirth NVARCHAR(max),
#BirthDate DATETIME,
#NationalCode BIGINT,
#Religion NVARCHAR(max),
#faith NVARCHAR(max),
#Nationality NVARCHAR(max),
#BloodGroup NVARCHAR(max),
#myID BIGINT output
AS
BEGIN
INSERT INTO [dbo].[usermainspecifications]
VALUES (#Name,
#Family,
#FatherName,
#BirthCertificate,
#PlaceOfBirth,
1,
#BirthDate,
#NationalCode,
#Religion,
#faith,
#Nationality,
#BloodGroup,
12,
'123',
'123',
1,
2015 - 1 - 1,
'12',
'123',
'1234',
1)
SELECT #myID = [userid]
FROM [mammutRecruitment].[dbo].[usermainspecifications]
WHERE [nationalcode] = #NationalCode
END

Conversion error when i call a stored procedure from SQL Server in C#

I have a stored procedure called lastID like this:
CREATE PROCEDURE lastID(#id varchar(64) OUTPUT)
AS
BEGIN
SET NOCOUNT ON;
DECLARE #f VARCHAR(64);
SELECT TOP 1 #f = work_id
FROM workorder
WHERE (RIGHT(work_id,2)) = (RIGHT(Year(getDate()),2))
ORDER BY work_id DESC;
IF(#f IS NULL)
BEGIN
SET #f = 'No work orders';
SET #id = #f;
RETURN #id;
END
ELSE
BEGIN
SET #id = #f;
RETURN #id;
END
END
This stored procedure returns the last id from the table workorder, now I'm trying to execute this procedure in C#, this is the code:
private void lastWorkId()
{
String strConnString = "Server=.\\SQLEXPRESS;Database=recalls;Integrated Security=true";
SqlConnection con = new SqlConnection(strConnString);
SqlCommand cmd = new SqlCommand();
cmd.CommandType = CommandType.StoredProcedure;
cmd.CommandText = "lastID";
cmd.Parameters.Add("#id", SqlDbType.VarChar, 64).Direction = ParameterDirection.Output;
cmd.Connection = con;
try
{
con.Open();
cmd.ExecuteNonQuery();
String id = cmd.Parameters["#id"].Value.ToString();
lastid.Text = id.ToString(); //Putting the return value into a label
}
catch (Exception ex)
{
throw ex;
}
finally
{
con.Close();
con.Dispose();
}
}
I don't know what are wrong with my code, because an exception is displayed, and this says
Conversion failed when converting the varchar value ' OT- 003-16 ' to data type int
I was wrong about my first answer, here is the updated answer:
Your stored procedure is setup with an OUTPUT parameter of type VARCHAR(64).
Within your proc you have a couple of RETURN #id; statements, which is actually returning a VARCHAR(64). You only need to set your OUTPUT variable within the stored procedure. The RETURN statement expects an integer expression. Here's the updated fixed sproc using OUTPUT appropriately:
ALTER PROCEDURE [dbo].[lastID](#id varchar(64) OUTPUT)
AS
BEGIN
SET NOCOUNT ON;
DECLARE #f VARCHAR(64);
SELECT TOP 1 #f = work_id FROM workorder WHERE (RIGHT(work_id,2)) = (RIGHT(Year(getDate()),2)) ORDER BY work_id DESC;
IF(#f IS NULL)
BEGIN
SET #f = 'No work orders';
SET #id = #f;
END
ELSE
BEGIN
SET #id = #f;
END
END
Error is basically should get fixed by cast
((RIGHT(work_id,2)) as int)
But code can be further condensed and improved.
CREATE PROCEDURE lastID(#id varchar(64) OUTPUT)
AS
BEGIN
SET NOCOUNT ON;
SELECT TOP 1 #id = isnull(work_id , 'No work orders') FROM workorder WHERE cast ((RIGHT(work_id,2)) as int)= (RIGHT(Year(getDate()),2)) ORDER BY work_id DESC;
RETURN #id;
END

Trying to use a SQL stored procedure in Windows Forms

The following code is causing problem in my Windows Forms app:
SqlConnection cnnDB = new SqlConnection(<connection string>);
try
{
SqlCommand cmd = cnnDB.CreateCommand();
cmd.CommandType = CommandType.StoredProcedure;
cmd.CommandText = "sp_ProcName";
cmd.Parameters.AddWithValue("#int1", ComboBox1.SelectedValue);
cmd.Parameters.AddWithValue("#int2", ComboBox2.SelectedValue);
cmd.Parameters.AddWithValue("#int3", ComboBox3.SelectedValue);
cmd.Parameters.AddWithValue("#int4", ComboBox4.SelectedValue);
cmd.Parameters.AddWithValue("#varchar1", TextBox1.Text);
cmd.Parameters.AddWithValue("#varchar2", TextBox2.Text);
cmd.Parameters.AddWithValue("#varchar3", ComboBox5.SelectedValue);
cmd.Parameters.AddWithValue("#varchar4", stringVariable);
cnnDB.Open();
cmd.ExecuteNonQuery();
cnnDB.Close();
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
This is what happens when I execute it:
If stringVariable is either "Insert" or "Update", data from TextBox1 and TextBox2 isn't passed to procedure.
If stringVariable is "Delete", I get error “Procedure or function ‘sp_ProcName’ expects parameter ‘#varchar3’, which was not supplied”.
Is there something wrong with the code?
EDIT: As requested by #Steve and #MethodMan, below is the stored procedure in SQL Server.
ALTER PROCEDURE [dbo].[sp_ProcName]
(
#int1 int,
#int2 int,
#int3 int,
#int4 int,
#varchar1 varchar(7),
#varchar2 varchar(6),
#varchar3 nvarchar(10),
#varchar4 nvarchar(10) = ''
)
AS
BEGIN
SET NOCOUNT ON;
IF #varchar4 = 'Insert'
BEGIN
INSERT INTO Table1(int1,int2,int3,int4,varchar1,varchar2,varchar3)
VALUES(#int1,#int2,#int3,#int4,#varchar1,#varchar2,#varchar3)
END
IF #varchar4 = 'Update'
BEGIN
UPDATE Table1
SET int1=#int1, int2=#int2, int3=#int3, int4=#int4, varchar1=#varchar1, varchar2=#varchar2, varchar3=#varchar3
WHERE varchar1 = #varchar1
END
IF #varchar4 = 'Delete'
BEGIN
DELETE FROM Table1
WHERE varchar1 = #varchar1
END
Well, after a closer examination, I see that the Update part in stored procedure is "bad egg". I'll need to find some other way. Delete part too.
P.S. Sorry for long question.
You need to use DBNull.Value instead of null or assign default values to your stored procedure parameters that might be missing:
Method 1 :
CREATE PROCEDURE [dbo].[problemParam]
// Other parameters go here then
#varchar1 NVARCHAR(50) = null,
#varchar1 NVARCHAR(50) = null,
#varchar1 NVARCHAR(50) = null,
AS
BEGIN
-- Procedure Logic go here
END
Method 2:
object param1 = DBNull.Value;
object param2 = DBNull.Value;
object param3 = DBNull.Value;
if(!String.IsNullOrEmpty(TextBox1.Text))
param1 = TextBox1.Text;
if(!String.IsNullOrEmpty(TextBox2.Text))
param2 = TextBox2.Text;
if(ComboBox5.SelectedValue != null)
param3 = TextBox1.Text;
cmd.Parameters.AddWithValue("#varchar1", param1 );
cmd.Parameters.AddWithValue("#varchar2", param2 );
cmd.Parameters.AddWithValue("#varchar3", param3 );

How to read Scope Identity in C# from executed Stored Procedure

I want to read Scope_Identity via output variable '#RoleID' from where I am assigning value of scope identity.
C#:
private static long createNewRoleInsert(ADB.Model.RolesModel roleModelObj, MSSQL sql)
{
bool killConnection = Utils.getConnection(ref sql);
long returnValue = 0;
try
{
sql.SetSProc("[dbo].[p_Role_dfn_createNew]");
sql.AddParam("#Title", roleModelObj.Title);
sql.AddParam("#Description", roleModelObj.Description);
sql.AddParam("#CreatedDate", roleModelObj.CreatedDate);
var RoleID = sql.ExecuteNonQuery();
if(RoleID!=0 && RoleID>0)
{
returnValue = RoleID;
}
}
finally
{
if (killConnection)
sql.Dispose();
}
return returnValue;
}
Stored procedure:
SET ANSI_NULLS ON
SET QUOTED_IDENTIFIER ON
GO
ALTER PROCEDURE [dbo].[p_Role_dfn_createNew]
#Title nvarchar(250),
#Description nvarchar(MAX) = NULL,
#CreatedDate DateTime,
#RoleID bigInt OUTPUT
AS
SET NOCOUNT ON;
SET XACT_ABORT ON
DECLARE #l_object AS SYSNAME = OBJECT_NAME(##PROCID),
#l_error_msg AS NVARCHAR(2000)
BEGIN TRY
BEGIN TRAN
INSERT INTO [adb_TestDb].[dbo].[Role] ([Title], [Description], [CreatedDate])
VALUES (#Title, #Description, #CreatedDate)
COMMIT TRAN
SET #RoleID = SCOPE_IDENTITY();
RETURN #RoleID
END TRY
BEGIN CATCH
-- rollback any open/uncomitted transactions
IF XACT_STATE() IN ( -1, 1) ROLLBACK TRANSACTION
-- return an error containing the object, error number and error description
SELECT #l_error_msg = 'Error number : ' + CAST(ERROR_NUMBER()AS VARCHAR) + '. ' + ERROR_MESSAGE()
RAISERROR (#l_error_msg,16,1)
END CATCH
The ExecuteNonQuery method doesn't return the return value from the procedure, it returns the number of rows affected.
To get the return value you would add a parameter with ParameterDirection.ReturnValue, however that won't safely get you the value in #RoleID as the return value from a procedure can't be a bigint, it's always an int.
As you already have #RoleID as an output parameter you should add parameter to the command to get the value. Example:
SqlParameter roleIdParam = new SqlParameter("#RoleID", SqlDbType.BigInt);
roleIdParam.Direction = ParameterDirection.Output;
cmd.Parameters.Add(roleIdParam);
// execute command
long roleId = (long)roleIdParam.Value;
You need to add an output parameter in C# to get the value of #RoleID from the stored procedure. Here's an example of that:
using System.Data.SqlClient;
using (SqlConnection conn = new SqlConnection("connectionString"))
{
SqlCommand cmd = conn.CreateCommand();
cmd.CommandType = System.Data.CommandType.StoredProcedure;
cmd.CommandText = "dbo.p_Role_dfn_createNew";
// add other parameters...
cmd.Parameters.Add(new SqlParameter("#RoleID", SqlDbType.BigInt))
.Direction = ParameterDirection.Output;
cmd.ExecuteNonQuery();
returnValue = (long)cmd.Parameters["#RoleID"].Value;
}
Change the
RETURN #RoleID
to
SELECT #RoleID
or add the output parameter as explained in other answers

returning int value from stored procedure and check it in asp.net code to validate login form

What is the true sequence to make this code run as I tried many time but I don't get a valid result
// the code of SQL stored procedure
set ANSI_NULLS ON
set QUOTED_IDENTIFIER ON
GO
ALTER PROC [dbo].[login_proc] #username Varchar =50, #password varchar=50
as
Declare #user_name varchar , #pass_word varchar, #result varchar
Set #user_name = #username
Set #pass_word = #password
if EXISTS (select username , password from data where username= #user_name)
set #result= 1
else
set #result=0
return #result
and asp.net code is
SqlConnection conn = new SqlConnection ("Data Source=ANAGUIB-LAPNEW\\SQLEXPRESS;Initial Catalog=account;Integrated Security=True");
SqlCommand cmd = new SqlCommand("login_proc",conn);
cmd.CommandType = CommandType.StoredProcedure;
SqlParameter paramReturnValue = new SqlParameter();
paramReturnValue.ParameterName = "#result";
paramReturnValue.SqlDbType = SqlDbType.Int;
cmd.Parameters.Add(paramReturnValue);
cmd.Parameters["#result"].Direction = ParameterDirection.Output;
conn.Open();
cmd.Parameters.AddWithValue("#username", TextBox1.Text);
cmd.Parameters.AddWithValue("#password", TextBox2.Text);
cmd.ExecuteScalar();
string retunvalue = (string)cmd.Parameters["#result"].Value;
if (retunvalue == "1")
{
Response.Redirect("hello.aspx");
}
else
{
Response.Write("error");
}
conn.Close();
You're executing .ExecuteScalar() so you're expecting back a result set with a single row, single column from the stored procedure - but you're not selecting anything at the end of your stored proc!
You need to change your last line in the stored proc from
return #result
to
SELECT #result
and then it should work.
Add another parameter for the return value
ALTER PROC [dbo].[login_proc]
#username Varchar = 50,
#password Varchar = 50,
#result int OUTPUT
Examples can be viewd here.
Did you try this one;
Use the
return #result
and in c#
int resultID = Convert.ToInt32(cmd.ExecuteScalar());
Also remove next line
cmd.Parameters[""].value;
I'm unable to login any suggestions, both in case of stored procedure and codebehind can anyone provide solution to this,,,plz,,,

Categories