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
)
Related
I get the error "42883: operator does not exist: integer =# integer" Npgsql.PostgresException
when trying to pass parameters to a DO block:
var cmd = new NpgsqlCommand();
cmd.CommandText =
#"DO $$
BEGIN
IF EXISTS (SELECT id FROM pub.table1 WHERE id = #id) THEN
UPDATE pub.table1
SET Field1 = #Field1
,Field2 = #Field2
WHERE id = #id;
ELSE
INSERT INTO pub.table1 (id, Field1, Field2)
VALUES (#id, #Field1, #Field2);
END IF;
END $$;";
cmd.Parameters.AddWithValue("#id", 1);
cmd.Parameters.AddWithValue("#Field1", "text");
cmd.Parameters.AddWithValue("#Field2", "text2");
Otherwise connection to postgres works and also (classic) queries work when passing parameters; e.g.:
cmd.CommandText = #"SELECT * FROM pub.table1 WHERE id = #id;";
Is it not possible to pass parameters to a "DO" block or am I missing something?
Thank you.
M
I am looking to Insert a row into a table and return the Identity column in c# code. I cannot seem to get the syntax quite right.
Here is the storted procedure
ALTER PROCEDURE [dbo].[sp_InsertIssue]
#Application nchar(20) = NULL ,
#Version nchar(10) = NULL ,
#CreatedBy NVARCHAR(30) = NULL ,
#AssignedTo nVARCHAR(max) = NULL ,
#Description nVARCHAR(max) = NULL ,
#UserId INT
AS
BEGIN
SET NOCOUNT ON
INSERT INTO dbo.Issue
(
Application ,
Version ,
CreatedBy ,
AssignedTo ,
Description ,
UserId
)
VALUES
(
#Application ,
#Version ,
#CreatedBy ,
#AssignedTo ,
#Description ,
#UserId
)
RETURN SCOPE_IDENTITY()
END
Here is the C# Code
SqlCommand cmd = new SqlCommand();
cmd.CommandText = "sp_InsertIssue ";
cmd.CommandType = System.Data.CommandType.StoredProcedure;
cmd.Connection = m_Connection;
SqlParameter parm = new SqlParameter("#IssueId", SqlDbType.Int);
parm.Direction = ParameterDirection.ReturnValue;
cmd.Parameters.Add("#Application", SqlDbType.VarChar).Value = p_Application;
cmd.Parameters.Add("#Version", SqlDbType.VarChar).Value = p_Version;
cmd.Parameters.Add("#CreatedBy", SqlDbType.VarChar).Value = p_CreatedBy;
cmd.Parameters.Add("#AssignedTo", SqlDbType.VarChar).Value = p_AssignedTo;
cmd.Parameters.Add("#Description", SqlDbType.VarChar).Value = p_Description;
cmd.Parameters.Add("#UserId", SqlDbType.Int).Value = p_UserId;
var returnParameter = cmd.Parameters.Add("IssueId", SqlDbType.Int);
returnParameter.Direction = ParameterDirection.ReturnValue;
/// send data to db
Int32 id = (int)cmd.ExecuteNonQuery();
Return -1 not the identity column
You have to make some changes :
SELECT SCOPE_IDENTITY() is beter than Return SCOPE_IDENTITY()
in your code you have to change also cmd.ExecuteNonQuery()
with int id = Convert.ToInt32(cmd.ExecuteScalar());
Changing my answer completely after reading your code more closely :) You were so close
Change:
Int32 id = (int)cmd.ExecuteNonQuery();
To:
cmd.ExecuteNonQuery(); // this returns the # of "rows affected"
Int32 id = (int)returnParameter.Value
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);
}
i have that code using LINQ to call a stored procedure to save some data into database then return two variables from the stored procedure.
[ASP.NET code]
dbDataContext dbo = new dbDataContext();
dbo.AddNewDoctor(doctorName, email, password, ref DocId, ref result);
[SQL]
create PROCEDURE [dbo].[AddNewDoctor]
#doctorname nvarchar(100),
#email nvarchar(100),
#password nvarchar(MAX),
#docId int out,
#Result int out
AS
BEGIN
SET NOCOUNT ON;
declare #idCounter int
select #idCounter = count(*) from dbo.doctors
if EXISTS (select * from dbo.doctors where e_mail = #email)
begin
SET #Result = -1
set #docId= 0
end
else
begin
INSERT INTO [dbo].[doctors]
([doctor_id]
,[doctorname]
,[e_mail]
,[password]
VALUES
((#idCounter +1)
,#docotorname
,#email
,#password
)
SET #Result = 1
set #docId= (#idCounter + 1)
end
END
this code work very well what i want to do now to use ADO instead of LINQ, the problem with me is that i can't pass the ref variable as in LINQ so how can i do it using ADO
You'll have to do something like this. Use ParameterDirection
SqlParameter output = new SqlParameter(paramName, dbType);
output.Direction = ParameterDirection.Output;
command.Parameters.Add(output);
In your case you've to use SqlDbType.Int. Use Value property to read return value.
SqlParameter output = new SqlParameter(paramName, SqlDbType.Int);
output.Direction = ParameterDirection.Output;
command.Parameters.Add(output);
int Result = (int) output.Value; or int? Result = (int?) output.Value;
Try this
using (SqlConnection con = new SqlConnection("Your connection string"))
{
con.Open();
SqlCommand mycommand = new SqlCommand();
mycommand.Connection = con;
mycommand.CommandText = "dbo.AddNewDoctor";
mycommand.CommandType = CommandType.StoredProcedure;
mycommand.Parameters.AddWithValue(doctorName);
mycommand.Parameters.AddWithValue(email);
mycommand.Parameters.AddWithValue(password);
mycommand.Parameters.AddWithValue(ref DocId);
mycommand.Parameters.AddWithValue(ref result);
mycommand.ExecuteNonQuery();
}
Hope this helps thanks.
Refer to this article, there is an working example:
http://csharp-guide.blogspot.de/2012/05/linq-to-sql-call-stored-procedure-with_25.html
I'm trying to get the inserted or updated id from a stored procedure, i tried 2 different ways
I'm not allowed to use If exists(select ....) for performance reason
1- using OUTPUT
#firstName varchar(30),
#Telephone int
AS
BEGIN transaction
UPDATE [PHONE_BOOK].[dbo].[USER]
SET TELEPHONE= #Telephone
output inserted.USERID
where FIRST_NAME = #firstName
if ##ROWCOUNT = 0
begin
INSERT INTO [PHONE_BOOK].[dbo].[USER]
([FIRST_NAME]
,[TELEPHONE])
output inserted.USERID -- or output SCOPE_IDENTITY()
VALUES
(#firstName
,#Telephone)
end
C# code
IList<SqlParameter> parameters = new List<SqlParameter>();
parameters.Add(new SqlParameter("#firstName", "Mike"));
parameters.Add(new SqlParameter("#Telephone", 9514256));
using (var sqlConnection = new SqlConnection(Config.ConnString))
{
sqlConnection.Open();
using (SqlCommand command = sqlConnection.CreateCommand())
{
command.CommandType = CommandType.StoredProcedure;
command.CommandText = "[dbo].[INSET_USER]";
command.UpdatedRowSource = UpdateRowSource.None;
foreach (SqlParameter oPar in parameters)
command.Parameters.Add(oPar);
object x = command.ExecuteScalar();
}
}
In case of update ==> x is Correct
In case of delete ==> x is null
2- using OUTPUT parameter
#firstName varchar(30),
#Telephone int,
#userId int output
AS
BEGIN transaction
UPDATE [PHONE_BOOK].[dbo].[USER]
SET TELEPHONE= #Telephone
where FIRST_NAME = #firstName
-- i can't find different way to set #userId than doing a select which is not acceptable
if ##ROWCOUNT = 0
begin
INSERT INTO [PHONE_BOOK].[dbo].[USER]
([FIRST_NAME]
,[TELEPHONE])
VALUES
(#firstName
,#Telephone)
set #userId = SCOPE_IDENTITY()
end
c# Code:
IList<SqlParameter> parameters = new List<SqlParameter>();
parameters.Add(new SqlParameter("#firstName", "Mike"));
parameters.Add(new SqlParameter("#Telephone", 9514256));
using (var sqlConnection = new SqlConnection(Config.ConnString))
{
sqlConnection.Open();
using (SqlCommand command = sqlConnection.CreateCommand())
{
command.CommandType = CommandType.StoredProcedure;
command.CommandText = "[dbo].[INSET_USER]";
command.UpdatedRowSource = UpdateRowSource.None;
foreach (SqlParameter oPar in parameters)
command.Parameters.Add(oPar);
command.Parameters.Add("#userId",0).Direction = ParameterDirection.Output;
command.ExecuteNonQuery();
var x = command.Parameters["#userId"].Value;
}
}
In case of update ==> x is -1
In case of delete ==> x is correct
how can i fix this? i perefere first option as i don't need to pass output parameter to the stored procedure
The reason you aren't getting your output value in this case is because you are *select*ing it rather than *return*ing it. You can pick it up from the first result set if you don't want to change your proc - but ExecuteScalar suppresses result sets, so you'll want to use ExecuteReader or something like that. However, there is a standard pattern for this and you aren't following it, so I'll post it just to be nice - I'm sure it's been covered elsewhere though.
Standard SP pattern -
create proc UpsertMyTable (
#parameter int
) AS
declare #result int
if exists (select 1 from MyTable where value = #parameter) begin
UPDATE HERE
end else begin
INSERT HERE
end
set #result = SCOPE_IDENTITY()
return #result
And then in your C# code, basically what you have in your example is correct except the way you've done the parameters is redundant and a performance problem...
using (var sqlConnection = new SqlConnection(Config.ConnString)) {
sqlConnection.Open();
using (SqlCommand command = sqlConnection.CreateCommand()) {
command.CommandType = CommandType.StoredProcedure;
command.CommandText = "[dbo].[PROC_UPSERT_SHARE]";
command.UpdatedRowSource = UpdateRowSource.None;
command.parameters.Add(new SqlParameter("#fullName", "dwfae"));
command.parameters.Add(new SqlParameter("#name", "aze"));
command.parameters.Add(new SqlParameter("#root", "aze"));
command.parameters.Add(new SqlParameter("#creationDate", new DateTime(2000, 10, 10)));
command.parameters.Add(new SqlParameter("#lastAccessDate", new DateTime(1999, 11, 11)));
command.parameters.Add(new SqlParameter("#lastWriteDate", new DateTime(1990,12,12)));
command.parameters.Add(new SqlParameter("#subShareCount", 20));
command.parameters.Add(new SqlParameter("#serverId", "serverx"));
object x = command.ExecuteScalar();
Console.WriteLine(x);
}
}
Something like that will be much faster. Please consider this type of thing even if you think the impact might be small.
Consider using RETURN or OUTPUT parameter along with ExecuteNonQuery(), it automatically populates values into the variables. ExecuteScalar() is not required.
http://blogs.msdn.com/b/spike/archive/2009/05/07/a-simple-example-on-how-to-get-return-and-out-parameter-values-using-ado-net.aspx