Why does SCOPE_IDENTITY() return -1? - c#

I have written this Stored Procedure:
ALTER PROCEDURE [cairs].[sp_SaveR]
-- Add the parameters for the stored procedure here
#fname nvarchar(50),
#lname nvarchar(50),
#mname nchar(10),
#sigDate date
AS
BEGIN
SET NOCOUNT ON;
insert into tUser
(fname,
lname,
mname,
sigDate
)
values
(
#fname,
#lname,
#mname,
#sigDate)
select SCOPE_IDENTITY()
END
This is the c# code I use to connect to it:
try
{
using (SqlConnection conn = new SqlConnection(cCon.getConn()))
{
using (SqlCommand cmd = conn.CreateCommand())
{
conn.Open();
cmd.CommandText = "sp_SaveR";
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.Add(new SqlParameter("#fname", fName));
cmd.Parameters.Add(new SqlParameter("#lname", lName));
cmd.Parameters.Add(new SqlParameter("#mname", mName));
cmd.Parameters.Add(new SqlParameter("#sigDate", sigDate));
int userID = (int)cmd.ExecuteNonQuery();
}
}
}
catch (Exception ex)
{
throw(ex);
}
My userID is always returning -1, even though the records are successfully inserted into the DB table. Why does this happen?

ExecuteNonQuery discards the result set. The number it returns is usually the number of rows affected, but it isn't something you can really rely on. In your case, it returns -1 because you're executing a stored procedure, it would return 1 if you inlined the SQL.
You want to use ExecuteScalar instead, which reads the first column from the first row in the first result set.

This is working as designed. The return value is the number of modified rows. If you are calling a stored proc or selecting data the value will be -1.
From MSDN...
SqlCommand.ExecuteNonQuery
For UPDATE, INSERT, and DELETE statements, the return value is the
number of rows affected by the command. When a trigger exists on a
table being inserted or updated, the return value includes the number
of rows affected by both the insert or update operation and the number
of rows affected by the trigger or triggers. For all other types of
statements, the return value is -1. If a rollback occurs, the return
value is also -1.

You should use output parameter to retrive id like as below.
ALTER PROCEDURE [cairs].[sp_SaveR]
-- Add the parameters for the stored procedure here
#fname nvarchar(50),
#lname nvarchar(50),
#mname nchar(10),
#sigDate date,
#NewId int OUTPUT
AS
BEGIN
SET NOCOUNT ON;
insert into tUser
(fname,
lname,
mname,
sigDate
)
values
(
#fname,
#lname,
#mname,
#sigDate)
select #NewId = SCOPE_IDENTITY()
END
In C#:
try
{
using (SqlConnection conn = new SqlConnection(cCon.getConn()))
{
using (SqlCommand cmd = conn.CreateCommand())
{
conn.Open();
cmd.CommandText = "sp_SaveR";
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.Add(new SqlParameter("#fname", fName));
cmd.Parameters.Add(new SqlParameter("#lname", lName));
cmd.Parameters.Add(new SqlParameter("#mname", mName));
cmd.Parameters.Add(new SqlParameter("#sigDate", sigDate));
cmd.Parameters.Add("#NewId", SqlDbType.Int).Direction = ParameterDirection.Output;
cmd.ExecuteNonQuery();
int userId = Convert.ToInt32(cmd.Parameters["#NewId"].Value);
}
}
}
catch (Exception ex)
{
throw(ex);
}

Related

Inserting data into SQL Server by using a stored procedure

I have a problem while inserting records into SQL Server.
The string from C# doesn't show up in SQL Server as I'm inserting the sql just insert the first char
Example: If I insert 22222 in the data base just the first 2 inserted
Note I'm using a stored procedure for my first time.
This is my code:
public void insert_workshop(DateTime Pdate, string PTime, string PDesc, byte[] Img)
{
SqlCommand cmd = new SqlCommand("[InsertWorkShops]", conn);
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.Add("#WorkshopsDate", SqlDbType.Date).Value = Pdate;
cmd.Parameters.Add("#Time", SqlDbType.NVarChar).Value = PTime;
cmd.Parameters.Add("#WorkshopsDescription", SqlDbType.NVarChar).Value = PDesc;
cmd.Parameters.Add("#WorkshopsImage", SqlDbType.Image).Value = Img;
cmd.Parameters.Add("#CreatedBy", SqlDbType.NVarChar).Value = 1;
try
{
cmd.ExecuteNonQuery();
Msg = "Add Done ";
}
catch
{
Msg = "Error While Adding";
}
WorkShopTransactions Ws = new WorkShopTransactions();
Ws.insert_workshop(WorkShopDT.Value, txtWorshopTime.Text.ToString(),
txtWorkshopDescriptions.Text.ToString(), img);
T-SQL:
ALTER PROCEDURE [dbo].[InsertWorkShops]
#WorkshopsDate date,
#Time nvarchar,
#WorkshopsDescription nvarchar,
#WorkshopsImage image,
#CreatedBy int
AS
BEGIN
SET NOCOUNT ON;
insert into Workshops
values(#WorkshopsDate, #Time, #WorkshopsDescription, #WorkshopsImage, #CreatedBy)
END
In the stored procedure, you have declared your nvarchar parameters without a length. They default to nvarchar(1).

MySQL. insert into stored procedure affected rows' count is always 0

I call a stored procedure from my c# code to insert a row into a table. My problem is that i always get 0 affected rows. Here are the codes
Stored procedure code
DELIMITER $$
CREATE DEFINER=`root`#`localhost` PROCEDURE `AddInfo`(
IN _activationDate datetime,
IN _organization varchar(100),
IN _email varchar(45),
IN _tableName varchar(35))
BEGIN
set #sqlquery = concat('insert into ', _tableName, ' values (?, ?, ?)');
prepare stmt from #sqlquery;
set #activationDate = _activationDate;
set #orgaization = _organization;
set #email = _email;
execute stmt using #activationDate, #orgaization, #email,;
deallocate prepare stmt;
END
C# code
using (MySqlConnection conn = new MySqlConnection(connStr))
{
string spName = "AddInfo";
MySqlCommand cmd = new MySqlCommand(spName, conn);
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.AddWithValue("#_activationDate", activationDate);
cmd.Parameters.AddWithValue("#_organization", organization);
cmd.Parameters.AddWithValue("#_email", email);
cmd.Parameters.AddWithValue("#_tableName", tableName);
conn.Open();
int rowsAffected = cmd.ExecuteNonQuery();
bool added = rowsAffected == 1 ? true : false;
conn.Close();
return added;
}
when i run this code the row is successfully added to the table, but rowsAffected is always 0. Where is my problem? Thank you

Stored procedure error when use computed column for ID

I got the error:
Procedure or function usp_User_Info3 has too many arguments specified
When I run the program. I don't know the error in SP or in C# code. I have to display the Vendor_ID after the user clicks the submit button. Where the thing going wrong here ?
Table structure :
CREATE TABLE User_Info3
(
SNo int Identity (2000,1) ,
Vendor_ID AS 'VEN' + CAST(SNo as varchar(16)) PERSISTED PRIMARY KEY,
UserName VARCHAR(16) NOT NULL,
User_Password VARCHAR(12) NOT NULL,
User_ConPassword VARCHAR(12) NOT NULL,
User_FirstName VARCHAR(25) NOT NULL,
User_LastName VARCHAR(25) SPARSE NULL,
User_Title VARCHAR(35) NOT NULL,
User_EMail VARCHAR(35) NOT NULL,
User_PhoneNo VARCHAR(14) NOT NULL,
User_MobileNo VARCHAR(14)NOT NULL,
User_FaxNo VARCHAR(14)NOT NULL,
UserReg_Date DATE DEFAULT GETDATE()
)
Stored Procedure :
ALTER PROCEDURE [dbo].[usp_User_Info3]
#SNo INT OUTPUT,
#Vendor_ID VARCHAR(10) OUTPUT,
#UserName VARCHAR(30),
#User_Password VARCHAR(12),
#User_ConPassword VARCHAR(12),
#User_FirstName VARCHAR(25),
#User_LastName VARCHAR(25),
#User_Title VARCHAR(35),
#User_OtherEmail VARCHAR(30),
#User_PhoneNo VARCHAR(14),
#User_MobileNo VARCHAR(14),
#User_FaxNo VARCHAR(14)
AS
BEGIN
SET NOCOUNT ON;
INSERT INTO User_Info3 (UserName,User_Password,User_ConPassword,User_FirstName,
User_LastName,User_Title,User_OtherEmail,User_PhoneNo,User_MobileNo,User_FaxNo)
VALUES (#UserName,#User_Password,#User_ConPassword,#User_FirstName,#User_LastName,
#User_Title,#User_OtherEmail,#User_PhoneNo,#User_MobileNo,#User_FaxNo)
SET #SNo = Scope_Identity()
SELECT Vendor_ID From User_Info3 WHERE SNo = #SNo
END
C# Code :
protected void BtnUserNext_Click(object sender, EventArgs e)
{
cmd.CommandType = CommandType.StoredProcedure;
cmd.CommandText = "usp_User_Info3";
System.Data.SqlClient.SqlParameter SNo=cmd.Parameters.Add("#SNo",System.Data.SqlDbType.Int);
System.Data.SqlClient.SqlParameter Vendor_ID=cmd.Parameters.Add("#Vendor_ID",
System.Data.SqlDbType.VarChar,10);
cmd.Parameters.Add("#UserName", SqlDbType.VarChar).Value = txtUserName.Text;
cmd.Parameters.Add("#User_Password", SqlDbType.VarChar).Value = txtRegPassword.Text;
cmd.Parameters.Add("#User_ConPassword", SqlDbType.VarChar).Value = txtRegConPassword.Text;
cmd.Parameters.Add("#User_FirstName", SqlDbType.VarChar).Value = txtRegFName.Text;
cmd.Parameters.Add("#User_LastName", SqlDbType.VarChar).Value = txtRegLName.Text;
cmd.Parameters.Add("#User_Title", SqlDbType.VarChar).Value = txtRegTitle.Text;
cmd.Parameters.Add("#User_OtherEmail", SqlDbType.VarChar).Value = txtOtherEmail.Text;
cmd.Parameters.Add("#User_PhoneNo", SqlDbType.VarChar).Value =txtRegTelephone.Text;
cmd.Parameters.Add("#User_MobileNo", SqlDbType.VarChar).Value =txtRegMobile.Text;
cmd.Parameters.Add("#User_FaxNo", SqlDbType.VarChar).Value =txtRegFax.Text;
cmd.Connection = SqlCon;
try
{
Vendor_ID.Direction = System.Data.ParameterDirection.Output;
SqlCon.Open();
cmd.ExecuteNonQuery();
string VendorID = cmd.ExecuteScalar() as string;
}
catch (Exception ex)
{
throw new Exception(ex.Message);
}
finally
{
string url = "../CompanyBasicInfo.aspx?Parameter=" + Server.UrlEncode(" + VendorID + ");
SqlCon.Close();
}
}
You're not setting the direction of the #SNo parameter
You're calling the command twice - Just call it with ExecuteScalar if you want the return value.
You're not setting the value of your #Vendor_ID output parameter in the stored procedure.
If I had to guess, I would wager that cmd is being re-used and has parameters from a previous call left in it. One option would be to call cmd.Parameters.Clear(), but frankly I see little point re-using this SqlCommand instance - it would be better to use a new command each time:
using(var cmd = SqlCon.CreateCommand()) {
cmd.CommandType = CommandType.StoredProcedure;
cmd.CommandText = "usp_User_Info3";
// TODO: add parameters
// TODO: call one of the Execute* methods
}
User_OtherEmail column doesnt exist in the table
Correct Stored Procedure
Create PROCEDURE [dbo].[usp_User_Info3]
#SNo INT OUTPUT,
#Vendor_ID VARCHAR(10) OUTPUT,
#UserName VARCHAR(30),
#User_Password VARCHAR(12),
#User_ConPassword VARCHAR(12),
#User_FirstName VARCHAR(25),
#User_LastName VARCHAR(25),
#User_Title VARCHAR(35),
#User_Email VARCHAR(30),
#User_PhoneNo VARCHAR(14),
#User_MobileNo VARCHAR(14),
#User_FaxNo VARCHAR(14)
AS
BEGIN
SET NOCOUNT ON;
INSERT INTO User_Info3 (UserName,User_Password,User_ConPassword,User_FirstName,
User_LastName,User_Title,User_Email,User_PhoneNo,User_MobileNo,User_FaxNo)
VALUES (#UserName,#User_Password,#User_ConPassword,#User_FirstName,#User_LastName,
#User_Title,#User_Email,#User_PhoneNo,#User_MobileNo,#User_FaxNo)
SET #SNo = Scope_Identity()
SELECT Vendor_ID From User_Info3 WHERE SNo = #SNo
END
and the c# code to be modified accordingly .
After all these answers from great minds I can't believe you are still stuck. Here are my suggestions
In your PROC
'maintain this in your parameter
#Vendor_ID VARCHAR(10) OUTPUT,
Update to Select VendorID into #VendorID. See the second line
SET #SNo = Scope_Identity()
SELECT #Vendor_ID=VendorID From User_Info3 WHERE SNo = #SNo
In C#, do not call ExecuteScalar use ExecuteNonQuery
string newVendorID = "";
try
{
Vendor_ID.Direction = System.Data.ParameterDirection.Output;
SqlCon.Open();
cmd.ExecuteNonQuery();
if(Vendor_ID.Value != null)
newVendorID = Vendor_ID.Value.ToString();
}
You could rename the Vendor_ID parameter to something more meaningful, like VendorIDParam. Hope this helps?
Thanks for all your response.After i modify many times the C# code and SP according to your ideas, finally i got the answer for my question. I removed 'Vendor_ID' from my SP and add few codes in my code as shown below.
Stored procedure :
ALTER PROCEDURE [dbo].[usp_User_Info3]
#SNo INT OUTPUT,
#UserName VARCHAR(30),
#User_Password VARCHAR(12),
#User_ConPassword VARCHAR(12),
#User_FirstName VARCHAR(25),
#User_LastName VARCHAR(25),
#User_Title VARCHAR(35),
#User_OtherEmail VARCHAR(30),
#User_PhoneNo VARCHAR(14),
#User_MobileNo VARCHAR(14),
#User_FaxNo VARCHAR(14)
AS
BEGIN
SET NOCOUNT ON;
INSERT INTO User_Info3 (UserName,User_Password,User_ConPassword,User_FirstName,User_Title,User_OtherEmail,User_PhoneNo,User_MobileNo,User_FaxNo)
VALUES (#UserName,#User_Password,#User_ConPassword,#User_FirstName,#User_LastName,#User_Title,#User_OtherEmail,#User_PhoneNo,#User_MobileNo,#User_FaxNo)
SET #SNo = Scope_Identity()
END
C# Code :
protected void BtnUserNext_Click(object sender, EventArgs e)
{
SqlCon.Open();
SqlCommand cmd2 = new SqlCommand("usp_User_Info3", SqlCon);
cmd2.CommandType = CommandType.StoredProcedure;
cmd2.CommandText = "usp_User_Info3";
System.Data.SqlClient.SqlParameter SNo=cmd2.Parameters.Add("#SNo", System.Data.SqlDbType.Int);
cmd2.Parameters.Add("#UserName", SqlDbType.VarChar).Value = txtUserName.Text.Trim();
cmd2.Parameters.Add("#User_Password", SqlDbType.VarChar).Value = txtRegPassword.Text.Trim();
cmd2.Parameters.Add("#User_ConPassword", SqlDbType.VarChar).Value = txtRegConPassword.Text;
cmd2.Parameters.Add("#User_FirstName", SqlDbType.VarChar).Value = txtRegFName.Text.Trim();
cmd2.Parameters.Add("#User_LastName", SqlDbType.VarChar).Value = txtRegLName.Text.Trim();
cmd2.Parameters.Add("#User_Title", SqlDbType.VarChar).Value = txtRegTitle.Text.Trim();
cmd2.Parameters.Add("#User_OtherEmail", SqlDbType.VarChar).Value = txtOtherEmail.Text.Trim();
cmd2.Parameters.Add("#User_PhoneNo", SqlDbType.VarChar).Value = txtRegCode1.Text;
cmd2.Parameters.Add("#User_MobileNo", SqlDbType.VarChar).Value = txtRegCode2.Text;
cmd2.Parameters.Add("#User_FaxNo", SqlDbType.VarChar).Value = txtRegCode3.Text;
cmd2.Connection = SqlCon;
try
{
SNo.Direction = System.Data.ParameterDirection.Output;
cmd2.ExecuteScalar();
string VendorID = "VEN" + cmd2.Parameters["#SNo"].Value.ToString();
}
finally
{
string url = "../CompanyBasicInfo.aspx?Parameter=" + Server.UrlEncode(" + VendorID + ");
ClientScript.RegisterStartupScript(this.GetType(), "callfunction", "alert('Login created successfully');window.location.href = '" + url + "';", true);
SqlCon.Close();
}
}

C# SQL stored procedure (which inserts) - pass parameters and retrieve parameter

I have a stored procedure on my server that inserts some parameters and returns the ID that was inserted. I am writing a form to do this easily but I cannot seem to get the parameter which is passed back.
To save you doing a whole bunch of possibly pointless reading, it's probably better to just pay attention to my C# code and let me know what I need to do in order to pass parameters and get one in return.
C# Default.aspx
connection = new SqlConnection(ConfigurationManager.AppSettings["ConnectionInfo"]);
sql = "aStoredProc";
command = new SqlCommand(sql, connection);
command.CommandType = CommandType.StoredProcedure;
command.Parameter.Add(new SqlParameter("#FirstName", SqlDbType.VarChar)).Value = sFirstname;
command.Parameter.Add(new SqlParameter("#SurName", SqlDbType.VarChar)).Value = sSurname;
connection.Open();
int ID = command.ExecuteNonQuery();
connection.Close();
SQL aStoredProc
IF EXISTS(SELECT * FROM aTable WHERE ID = #ID)
-- User exists, update details
BEGIN
BEGIN TRAN
UPDATE aTable
SET
FirstName = #FirstName,
SurName = #SurName,
LastUpdate = GetDate()
WHERE ID = #ID
IF (##Error != 0)
ROLLBACK TRAN
ELSE
COMMIT TRAN
END
ELSE
-- New user
BEGIN
BEGIN TRAN
INSERT aTable (
FirstName,
SurName,
GetDate()
)
VALUES (
#FirstName,
#SurName,
#LastUpdate
)
SELECT #ID = ##IDENTITY
IF (##Error != 0)
ROLLBACK TRAN
ELSE
COMMIT TRAN
END
The parameter #ID is listed in the stored proc as:
#ID (int, Input/Output, No default)
and proc has 'Return integer'. This used to work fine with a VBA solution prior to a SQL Server 2005 upgrade.
Thanks in advance.
connection = new SqlConnection(ConfigurationManager.AppSettings["ConnectionInfo"]);
sql = "aStoredProc";
command = new SqlCommand(sql, connection);
command.CommandType = CommandType.StoredProcedure;
command.Parameter.Add(new SqlParameter("#FirstName", SqlDbType.VarChar)).Value = sFirstname;
command.Parameter.Add(new SqlParameter("#SurName", SqlDbType.VarChar)).Value = sSurname;
command.Parameter.Add(new SqlParameter("#SurName", SqlDbType.VarChar)).Value = sSurname;
SqlParameter ParamId = cmd.Parameters.Add( "#Id", SqlDbType.Int);
ParamId.Direction = ParameterDirection.InputOutput;
command.Parameter.Add(ParamId);
connection.Open();
command.ExecuteNonQuery();
int ID = ParamId.Value;
connection.Close();
you have to add output paramter in Parameter collection.
Read Value like above.
You have an error in your SQL, it should look like this:
INSERT aTable (FirstName,SurName,LastUpdate)
VALUES (#FirstName, #SurName, GetDate() )
Not like this:
INSERT aTable (
FirstName,
SurName,
GetDate()
)
VALUES (
#FirstName,
#SurName,
#LastUpdate
)

How to modify Stored Procedure or ASP.net Code to get autogenerated Id after inserting new row

I m creating new user registration moduleand for that i wrote following stored proc.
PROCEDURE [dbo].[addNewUser]
-- Add the parameters for the stored procedure here
#usertype VarChar(10),
#useremail VarChar(70),
#userpass VarChar(20),
#fullname VarChar(70),
#city VarChar(70),
#state Int,
#allowAlerts Bit,
#allowLetter Bit,
#aboutMe NVARCHAR(160)
As
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
if ((select count(user_info._id) from user_info where useremail like #useremail) = 0)
BEGIN
Insert Into user_info
(usertype,useremail,userpass,fullname,city,[state],allowAlerts,allowLetters,aboutMe)
Values
(
#usertype,
#useremail,
#userpass ,
#fullname,
#city,
#state,
#allowAlerts,
#allowLetter,
#aboutMe
)
Select ##IDENTITY as NewID
END
Else
BEGIN
Print '-1'
END
And following is the simple ASP.net C# Code that I try to use
public int registerNewUser(string usertype, string useremail, string userpass, string fullname, string city, string state, string allowAlerts, string allowLetter, string aboutMe)
{
con = new SqlConnection(connectionString);
cmd = new SqlCommand();
cmd.Connection = con;
cmd.CommandType = CommandType.StoredProcedure;
cmd.CommandText = "addBlogEntry";
cmd.Parameters.Add("#usertype", SqlDbType.VarChar).Value = usertype;
cmd.Parameters.Add("#useremail", SqlDbType.VarChar).Value = useremail;
cmd.Parameters.Add("#userpass", SqlDbType.VarChar).Value = userpass;
cmd.Parameters.Add("#fullname", SqlDbType.VarChar).Value = fullname;
cmd.Parameters.Add("#city", SqlDbType.VarChar).Value = city;
cmd.Parameters.Add("#state", SqlDbType.VarChar).Value = Convert.ToInt16(state);
cmd.Parameters.Add("#allowAlerts", SqlDbType.VarChar).Value = Convert.ToInt16(allowAlerts);
cmd.Parameters.Add("#allowLetter", SqlDbType.VarChar).Value = Convert.ToInt16(allowLetter);
cmd.Parameters.Add("#aboutMe", SqlDbType.VarChar).Value = aboutMe;
try
{
if (con.State != ConnectionState.Open)
con.Open();
cmd.ExecuteNonQuery();
con.Close();
con.Dispose();
// some code to be written here so that i can return userID(success) or -1(if that username is already registered)
return 0;
}
catch (Exception Ex)
{
con.Close();
con.Dispose();
return 0;
}
}
Through my C# code i want to return either auto generated userId which my stored procedures returns to me or if user alrady exists than i want to return -1
Please tell how to do this?
Thanks in advance :)
Yes, you can use ExecuteScalar() and change
Print '-1'
into
Select -1 as NewID
First of all, you should use SELECT SCOPE_IDENTITY() inside your stored proc to retrieve the new ID value (##IDENTITY can return false results).
And yes, if you want to get the result back, you need to call either .ExecuteScalar() or .ExecuteReader() and then read that value back.
And while you're at it - I'd also recommend putting your SqlConnection and SqlCommand objects into using blocks - so instead of your code, use this:
using(con = new SqlConnection(connectionString))
using(cmd = new SqlCommand(con))
{
..... // put the rest of your code here
}
If you want to create an output parameter for your stored proc, and set it to the new key you can access it that way. ExecuteNonQuery will return the number of rows affected, so that can be used as well. Something like this:
cmd.Parameters.Add("#uniquID", SqlDbType.Int).Direction = ParameterDirection.Output;
// Your other code...
var result = cmd.ExecuteNonQuery();
// Your other code...
return (result == 1) ? (int)cmd.Parameters["#uniquID"].Value : -1;

Categories

Resources