I'm attempting to retrieve an integer value from a single table, based on the string field username. I've tried it using a stored proc, and direct text. When I execute the stored proc, I get the proper return value; however, the proper result doesn't come through.
Here are both sets of code -
Direct text -
public int GetUserRole(string CUSER)
{
try
{
SQLCON = new SqlConnection(connectionString);
SQLCON.Open();
SQLCommand = new SqlCommand();
SQLCommand.CommandType = CommandType.Text;
SQLCommand.Parameters.Add("USUsername", SqlDbType.VarChar).Value = CUSER;
SQLCommand.CommandText = "SELECT USRole FROM tblUser WHERE USUsername = CUSER";
Int32 USRole = (Int32) SQLCommand.ExecuteScalar();
return USRole;
}
catch
{
HttpContext.Current.Response.Redirect("~/ErrorRedirect.aspx", false);
return 0;
}
}
SQL query:
ALTER PROCEDURE [dbo].[spGetUserRole]
-- Add the parameters for the stored procedure here
#username VARCHAR(50)
AS
BEGIN
-- Declare the return variable here
DECLARE #USRole as int
-- Add the T-SQL statements to compute the return value here
SELECT #USRole = tblUser.USRole FROM tblUser WHERE USUsername = #username
-- Return the result of the function
RETURN #USRole
END
You are not referencing your parameter correctly. If you are adding a parameter named USUsername then in the command text you should use #USUsername:
public int GetUserRole(string CUSER)
{
try
{
SQLCON = new SqlConnection(connectionString);
SQLCON.Open();
SQLCommand = new SqlCommand();
SQLCommand.CommandType = CommandType.Text;
SQLCommand.Parameters.Add("USUsername", SqlDbType.VarChar).Value = CUSER;
SQLCommand.CommandText = "SELECT USRole FROM tblUser WHERE USUsername = #USUsername";
Int32 USRole = (Int32) SQLCommand.ExecuteScalar();
return USRole;
}
catch (Exception)
{
HttpContext.Current.Response.Redirect("~/ErrorRedirect.aspx", false);
return 0;
}
}
Your stored procedure will also need updating as the parameter name here should also match and you don't need the return variable.
ALTER PROCEDURE [dbo].[spGetUserRole]
-- Add the parameters for the stored procedure here
#USUsername VARCHAR(50)
AS
BEGIN
-- Add the T-SQL statements to compute the return value here
SELECT tblUser.USRole FROM tblUser WHERE USUsername = #USUsername
END
You should also look at using the "using" syntax to automatically close your database connections. See Scott Hanselman's example here - http://www.hanselman.com/blog/WhyTheUsingStatementIsBetterThanASharpStickInTheEyeAndASqlConnectionRefactoringExample.aspx
Instead of using the return value of the stored procedure (RETURN #USRole), send the results back using a Select statement (e.g. Select #USRole). What is going on is that the return value of a stored procedure isn't the same as what is used by ExecuteScalar. ExecuteScalar returns the first column and row of the output. The return value is different and must accessed using the specially named parameter #RETURN_VALUE or the special ParameterDirection.ReturnValue property.
A revised version of your procedure would look like:
ALTER PROCEDURE [dbo].[spGetUserRole]
-- Add the parameters for the stored procedure here
#USUsername VARCHAR(50)
AS
BEGIN
-- Add the T-SQL statements to compute the return value here
Select tblUser.USRole
FROM tblUser
WHERE USUsername = #USUsername
END
RETURN (Transact-SQL)
SqlCommand.ExecuteScalar Method
I dont know how you called your stored procedure, but theres a bug in the query that you posted:
"SELECT USRole FROM tblUser WHERE USUsername = CUSER"
should be replaced with
SQLCommand.Parameters.Add("#USUsername", SqlDbType.VarChar).Value = CUSER;
"SELECT USRole FROM tblUser WHERE USUsername = #USUsername"
You are currently not really making the parameter part of the query, but trying to find the value CUSER within the column
Use parameter correctly. And dont forget to close connection on finally statement.
public int GetUserRole(string CUSER)
{
try
{
SQLCON = new SqlConnection(connectionString);
SQLCON.Open();
SQLCommand = new SqlCommand();
SQLCommand.CommandType = CommandType.Text;
SQLCommand.CommandText = "SELECT USRole FROM tblUser WHERE USUsername = #USUsername ";
SQLCommand.Parameters.Add("USUsername", SqlDbType.VarChar).Value = CUSER;
Int32 USRole = (Int32) SQLCommand.ExecuteScalar();
return USRole;
}
catch (Exception)
{
HttpContext.Current.Response.Redirect("~/ErrorRedirect.aspx", false);
return 0;
}
finally { close connection here.. }
}
If you insist on using the return value you can do it by setting the Parameter direction and using ExecuteNonQuery
SqlParameter p = cmd.Parameters.Add("#USRole", SqlDbType.Int);
p.Direction = ParameterDirection.ReturnValue;
cmd.ExecuteNonQuery();
int returnvalue = (int)cmd.Parameters["#USRole"].Value;
If you want to use ExecuteScalar then just change your proc to select the variable instead of Return
You should note that what you put in for the parameter name is arbitrary.
Related
So I am storing a value which is the student reference number which I have done, not I need to return the value from my ID and my DateTime in textbox2 and textbox 3. Whilst inputting and executing the procedure.
using (SqlConnection con = new *****))
{
SqlCommand cmd = con.CreateCommand();
cmd.CommandText = "Exams_BagCheck_ScanIn";
{
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.AddWithValue("#StudentReference", SqlDbType.VarChar).Value = textBox1.Text;
cmd.Parameters.AddWithValue("#ID", SqlDbType.Int).Direction = ParameterDirection.ReturnValue;
con.Open();
cmd.ExecuteNonQuery();
The procedure
USE [IFCustom]
GO
DECLARE #return_value Int
EXEC #return_value = [dbo].[Exams_BagCheck_ScanIn]
#StudentReference = N'1'
SELECT #return_value as 'Return Value'
GO
Your procedure returns nothing, you need to remove:
SELECT #return_value as 'Return Value'
And instead:
RETURN #return_value
(If you wanted to select then .ExecuteScalar() would return the value)
If you just returning a single value then you can use
this:
string some_value = cmd.ExecuteScalar().ToString(); // if it is string
OR
Object some_value = cmd.ExecuteScalar(); // convert it to its repective type.
in place of
cmd.ExecuteNonQuery();
//some_value will contain the value you selected as SELECT #return_value in procedure.
I am inserting a data row into my SQL Server database and then I want to query the data to get the unique identifier from the inserted row but my SqlDataReader is returning an empty dataset. I am thinking it maybe that the transaction hasn't been committed or something like that but I am not sure. I do not get an error.
Here is my code:
try
{
strQuery = "INSERT INTO clientnames VALUES(NEWID(),'" + txtACLastName.Text + "','" + txtACFirstName.Text + "'," + 1 + ")";
using (SqlCommand sqlInsertCmd = new SqlCommand(strQuery, sqlConn))
{
intQueryResult = sqlInsertCmd.ExecuteNonQuery();
if (intQueryResult == 0)
{
blnSuccess = false;
goto InsertClientNamesError;
}
else
{
blnSuccess = true;
}
sqlInsertCmd.Dispose();
}
if (blnSuccess)
{
strQuery = "select clientID from clientnames where firstname = '" + txtACFirstName.Text + "' and lastname = '" + txtACLastName.Text + "'";
using (SqlCommand sqlSelectCmd = new SqlCommand(strQuery, sqlConn))
{
SqlDataReader sqlDataRead = sqlSelectCmd.ExecuteReader();
while (sqlDataRead.Read())
{
strClientID = sqlDataRead.ToString();
}
sqlDataRead.Close();
sqlSelectCmd.Dispose();
}
}
}
catch (Exception exQuery)
{
System.Windows.MessageBox.Show("InsertClientNames: Error, " + exQuery.Message + ", has occurred.");
}
You are not getting the desired result because perhaps the SqlConnection is not opened explicitly (just a guess hard to tell without having full code). But this link shows you how to read from reader --> https://msdn.microsoft.com/en-us/library/haa3afyz(v=vs.110).aspx
But I suggest that you Please do not do it this way. Reason is you are making Two round trips to the DB Server when only one would have done the job for you IF you were using stored procedures. Also you are exposing yourselves to SQL Injection attacks as you are not parameterizing your queries.
Stored procedure:
CREATE PROCEDURE dbo.INS_clientnames
(
#FirstName varchar(100),
#LastName varchar(100),
#NewID int out
)
AS
BEGIN
Declare #Err int
set #NewID = NewID() -- Get the New ID and store it in the variable ( #NewID ) that the SP will return back to the caller
INSERT INTO clientnames values (#NewID , #FirstName , #LastName)
SET #Err = ##ERROR
IF #Error <> 0 -- Check If there was an error
Begin
SET #NewID = -1 -- Indicates that there was an error. You could log this into a Log Table with further details like error id and name.
END
RETURN
END
C# code to execute the above stored procedure and get the NewID:
using(SqlConnection conn = new SqlConnection(connectionString ))
{
using(SqlCommand cmd = new SqlCommand("dbo.INS_clientnames", conn))
{
cmd.CommandType = CommandType.StoredProcedure;
// set up the parameters that the Stored Procedure expects
cmd.Parameters.Add("#FirstName", SqlDbType.VarChar, 100);
cmd.Parameters.Add("#LastName" , SqlDbType.VarChar, 100);
cmd.Parameters.Add("#NewId" , SqlDbType.Int).Direction = ParameterDirection.Output;
// set parameter values that your code will send to the SP as parameter values
cmd.Parameters["#FirstName"].Value = txtACFirstName.Text ;
cmd.Parameters["#LastName"].Value = txtACLastName.Text ;
// open connection and execute stored procedure
conn.Open();
cmd.ExecuteNonQuery();
// read output value from #NewId
int NewID = Convert.ToInt32(cmd.Parameters["#NewId"].Value);
}
}
Add the following line to your stored procedure that inserts the record
SELECT SCOPE_IDENTITY()
This will return the last identity value inserted in that table.
And use cmd.ExecuteScalar() instead of ExecuteNonQuery()
ExecuteScalar() 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. [More info][1]
I see two approaches to do this:
either you generate the new GUID on the client side in your C# code and pass it into the query - then you already know what the new id is going to be, so you don't need to do a second query to get it:
you create your GUID on the server side and return it to the caller using the OUTPUT clause in your query
Approach #1:
// define connection string and query
string connStr = "--your connection string here--";
string query = "INSERT INTO dbo.Clients(ClientID, FirstName, LastName) VALUES(#ID, #First, #Last);";
using (SqlConnection conn = new SqlConnection(connStr))
using (SqlCommand cmd = new SqlCommand(query, conn))
{
// create the GUID in C# - this is the ID - no need to go get it again - this *IS* the id
Guid id = Guid.NewGuid();
// set the parameters
cmd.Parameters.Add("#ID", SqlDbType.UniqueIdentifier).Value = id;
cmd.Parameters.Add("#First", SqlDbType.VarChar, 50).Value = "Peter";
cmd.Parameters.Add("#Last", SqlDbType.VarChar, 50).Value = "Miller";
// open connection, execute query, close connection
conn.Open();
cmd.ExecuteNonQuery();
conn.Close();
}
Approach #2:
// define connection string and query
string connStr = "--your connection string here--";
// query has an "OUTPUT" clause to return a newly inserted piece of data
// back to the caller, just as if a SELECT had been issued
string query = "INSERT INTO dbo.Clients(ClientID, FirstName, LastName) OUTPUT Inserted.ClientID VALUES(NEWID(), #First, #Last);";
using (SqlConnection conn = new SqlConnection(connStr))
using (SqlCommand cmd = new SqlCommand(query, conn))
{
// set the parameters - note: you do *NOT* send in a GUID value - the NEWID() will create one automatically, on the server
cmd.Parameters.Add("#First", SqlDbType.VarChar, 50).Value = "Frank";
cmd.Parameters.Add("#Last", SqlDbType.VarChar, 50).Value = "Brown";
// open connection
conn.Open();
// execute query and get back one row, one column - the value in the "OUTPUT" clause
object output = cmd.ExecuteScalar();
Guid newId;
if (Guid.TryParse(output.ToString(), out newId))
{
//
}
conn.Close();
}
I have this stored procedure:
create procedure sp_findMaxEmployee
#maxID as varchar(10) OUTPUT
as
SET #maxID = (SELECT MAX(e_ID) FROM Employee)
go
I try to register an output parameter like this:
public string generateID()
{
connection = new SqlConnection(connectionStr);
cmd = new SqlCommand("sp_findMaxEmployee", connection);
SqlParameter param = new SqlParameter();
param.ParameterName = "#maxID";
param.Direction = ParameterDirection.Output;
param.SqlDbType = SqlDbType.VarChar;
cmd.Parameters.Add(param);
connection.Open();
cmd.ExecuteNonQuery();
connection.Close();
return cmd.Parameters["#maxID"].Value.ToString();
}
I tried to execute this procedure in SQL and it return right value, but when I execute project in debug mode, it shows me error:
String[0]: the Size property has an invalid size of 0.
Null value? Can you help me, thank you so much!
Assuming e_ID is a integer, you can just perform a SELECT and ExecuteScalar to return a single value:
create procedure sp_findMaxEmployee
as
SELECT MAX(e_ID) FROM Employee
go
Then in code, something like:
public string generateID()
{
connection = new SqlConnection(connectionStr);
cmd = new SqlCommand("sp_findMaxEmployee", connection);
connection.Open();
var maxId = cmd.ExecuteScalar();
connection.Close();
return maxId.ToString();
}
Finally, there's probably a deeper question as to why you are returning the last ID, hopefully it's not to get the next available ID, which you should let SQL do on your behalf by letting it auto-increment.
Little Tweak for SP
The Tweak is not necessary but it looks better this way :) and also please avoid using sp_ prefix for your stored procedures. Use usp_ instead.
create procedure usp_findMaxEmployee
#maxID as varchar(10) OUTPUT
AS
BEGIN
SET NOCOUNT ON;
SELECT #maxID = MAX(e_ID) FROM Employee;
END
Calling from Code
public string generateID()
{
SqlConnection conn = new SqlConnection(connectionStr);
SqlCommand cmd = new SqlCommand("usp_findMaxEmployee", conn);
cmd.CommandType = CommandType.StoredProcedure;
// set up the parameters
cmd.Parameters.Add("#maxID", SqlDbType.VarChar, 10).Direction = ParameterDirection.Output;
// open connection and execute stored procedure
conn.Open();
cmd.ExecuteNonQuery();
// read output value from #maxID
String maxID = Convert.ToString(cmd.Parameters["#maxID"].Value);
conn.Close();
return maxID;
}
Note
Use the using block of Try/Catch/Finnaly blocks to close connection if anything goes wrong.
You need to specify a .Size for your parameter. Your stored procedure specifies an output of varchar(10), so you should set the param.Size = 10;
You need to specify that cmd.CommandType = CommandType.StoredProcedure, the default CommandType is CommandType.Text
Make those changes and your method works as you intended.
I have a stored procedure, which returns the unique identifier after insertion ##identity. I tried it in the server explorer and it works as expected #RETURN_VALUE = [identifier].
In my code I added a parameter called #RETURN_VALUE, with ReturnValue direction first, than any other parameters, but when I run my query with ExecuteNonQuery() that parameter remains empty. I don't know what I've done wrong.
Stored Procedure
ALTER PROCEDURE dbo.SetAuction
(
#auctionID int,
#itemID int,
#auctionType tinyint,
#reservationPrice int,
#maxPrice int,
#auctionEnd datetime,
#auctionStart datetime,
#auctionTTL tinyint,
#itemName nchar(50),
#itemDescription nvarchar(MAX),
#categoryID tinyint,
#categoryName nchar(50)
) AS
IF #auctionID <> 0
BEGIN
BEGIN TRAN T1
UPDATE Auction
SET AuctionType = #auctionType,
ReservationPrice = #reservationPrice,
MaxPrice = #maxPrice,
AuctionEnd = #auctionEnd,
AuctionStart = #auctionStart,
AuctionTTL = #auctionTTL
WHERE AuctionID = #auctionID;
UPDATE Item
SET
ItemName = #itemName,
ItemDescription = #itemDescription
WHERE
ItemID = (SELECT ItemID FROM Auction WHERE AuctionID = #auctionID);
COMMIT TRAN T1
RETURN #auctionID
END
ELSE
BEGIN
BEGIN TRAN T1
INSERT INTO Item(ItemName, ItemDescription, CategoryID)
VALUES(#itemName, #itemDescription, #categoryID);
INSERT INTO Auction(ItemID, AuctionType, ReservationPrice, MaxPrice, AuctionEnd, AuctionStart, AuctionTTL)
VALUES(##IDENTITY,#auctionType,#reservationPrice,#maxPrice,#auctionEnd,#auctionStart,#auctionTTL);
COMMIT TRAN T1
RETURN ##IDENTITY
END
C# Code
cmd.CommandText = cmdText;
SqlParameter retval = new SqlParameter("#RETURN_VALUE", System.Data.SqlDbType.Int);
retval.Direction = System.Data.ParameterDirection.ReturnValue;
cmd.Parameters.Add(retval);
cmd.Parameters.AddRange(parameters);
cmd.Connection = connection;
connection.Open();
cmd.ExecuteNonQuery();
return (int)cmd.Parameters["#RETURN_VALUE"].Value;
Just tried on my box and this works for me:
In SQL Server:
DROP PROCEDURE TestProc;
GO
CREATE PROCEDURE TestProc
AS
RETURN 123;
GO
In C#
string cnStr = "Server=.;Database=Sandbox;Integrated Security=sspi;";
using (SqlConnection cn = new SqlConnection(cnStr)) {
cn.Open();
using (SqlCommand cmd = new SqlCommand("TestProc", cn)) {
cmd.CommandType = CommandType.StoredProcedure;
SqlParameter returnValue = new SqlParameter();
returnValue.Direction = ParameterDirection.ReturnValue;
cmd.Parameters.Add(returnValue);
cmd.ExecuteNonQuery();
Assert.AreEqual(123, (int)returnValue.Value);
}
}
I solved the problem:
you have to set SqlCommand.CommandType to CommandType.StoredProcedure in order to get return values and/or output parameters. I haven't found any documentation about that, but now everything works.
Do you get the value of you EXEC in TSQL? I wonder if refactoring the TSQL would help (and using SCOPE_IDENTITY():
so change:
COMMIT TRAN T1
RETURN ##IDENTITY
to:
SET #auctionID = SCOPE_IDENTITY()
COMMIT TRAN T1
RETURN #auctionID
(I would also change the other ##IDENTITY to SCOPE_IDENTITY())
As a minor optimisation, you could also use:
return (int)retval.Value;
but this side of things should have worked "as is" from what I can see (hence why I'm focusing on the TSQL).
Some one can also use this simple and short method to calculate return value from SP
In SQL:
Create Table TestTable
(
Int Id
)
CREATE PROCEDURE Proc_TestProc
#Id
AS
Begin
Set NOCOUNT ON //Use this line if you don't want to return any message from SQL
Delete from TestTable where Id = #Id
return 1
Set NOCOUNT OFF //NOCOUNT OFF is Optional for NOCOUNT ON property
End
Sql Server always returns Int type value only.
and in C#
using (SqlConnection conn = new SqlConnection(System.Configuration.ConfigurationManager.ConnectionStrings["TestConnectionString"].ToString()))
using (SqlCommand cmd = new SqlCommand("Proc_TestProc", conn))
{
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.AddWithValue("#Id", 1);
var returnParameter = cmd.Parameters.Add("#ReturnVal", SqlDbType.Int);
returnParameter.Direction = ParameterDirection.ReturnValue;
conn.Open();
cmd.ExecuteNonQuery();
var result = returnParameter.Value;
}
You can also check your return value in SQL by using this command:
DECLARE #return_status int;
EXEC #return_status = dbo.[Proc_TestProc] 1;
SELECT 'Return Status' = #return_status;
print 'Returned value from Procedure: ' + Convert(varchar, #return_status); // Either previous or this line both will show you the value of returned value
you can use standart ways that you use before in normal queries but in Sql command you must write EXEC before your store procedure name and dont use commandtype like this :
SqlConnection con = new SqlConnection(["ConnectionString"])
SqlCommand com = new SqlCommand("EXEC _Proc #id",con);
com.Parameters.AddWithValue("#id",["IDVALUE"]);
con.Open();
SqlDataReader rdr = com.ExecuteReader();
ArrayList liste = new ArrayList();
While(rdr.Read())
{
liste.Add(rdr[0]); //if it returns multiple you can add them another arrays=> liste1.Add(rdr[1]) ..
}
con.Close();
I have the following query:
set ANSI_NULLS ON
set QUOTED_IDENTIFIER ON
go
ALTER PROCEDURE [dbo].[Validate]
#a varchar(50),
#b varchar(50) output
AS
SET #Password =
(SELECT Password
FROM dbo.tblUser
WHERE Login = #a)
RETURN #b
GO
This compiles perfectly fine. I want to execute this query and get the return value. My code is below:
SqlConnection SqlConn = new SqlConnection(System.Configuration.ConfigurationManager.ConnectionStrings["MyLocalSQLServer"].ConnectionString.ToString());
System.Data.SqlClient.SqlCommand sqlcomm = new System.Data.SqlClient.SqlCommand("Validate", SqlConn);
string returnValue = string.Empty;
try
{
SqlConn.Open();
sqlcomm.CommandType = CommandType.StoredProcedure;
SqlParameter param = new SqlParameter("#a", SqlDbType.VarChar);
param.Direction = ParameterDirection.Input;
param.Value = Username;
sqlcomm.Parameters.Add(param);
SqlParameter retval = sqlcomm.Parameters.Add("#b", SqlDbType.VarChar);
retval.Direction = ParameterDirection.ReturnValue;
string retunvalue = (string)sqlcomm.Parameters["#b"].Value;
Note: Exception handling cut to keep the code short. Everytime I get to the last line, null is returned. What's the logic error with this code?
Mehrdad makes some good points, but the main thing I noticed is that you never run the query...
SqlParameter retval = sqlcomm.Parameters.Add("#b", SqlDbType.VarChar);
retval.Direction = ParameterDirection.ReturnValue;
sqlcomm.ExecuteNonQuery(); // MISSING
string retunvalue = (string)sqlcomm.Parameters["#b"].Value;
retval.Direction = ParameterDirection.Output;
ParameterDirection.ReturnValue should be used for the "return value" of the procedure, not output parameters. It gets the value returned by the SQL RETURN statement (with the parameter named #RETURN_VALUE).
Instead of RETURN #b you should SET #b = something
By the way, return value parameter is always int, not string.
I was having tons of trouble with the return value, so I ended up just selecting stuff at the end.
The solution was just to select the result at the end and return the query result in your functinon.
In my case I was doing an exists check:
IF (EXISTS (SELECT RoleName FROM dbo.Roles WHERE #RoleName = RoleName))
SELECT 1
ELSE
SELECT 0
Then
using (SqlConnection cnn = new SqlConnection(ConnectionString))
{
SqlCommand cmd = cnn.CreateCommand();
cmd.CommandType = CommandType.StoredProcedure;
cmd.CommandText = "RoleExists";
return (int) cmd.ExecuteScalar()
}
You should be able to do the same thing with a string value instead of an int.
This is building on Joel's and Mehrdad's answers: you're never binding the parameter of the retval to the sqlcommand. You need a
sqlcomm.Parameters.Add(retval);
and to make sure you're running the command
sqlcomm.ExecuteNonQuery();
I'm also not sure why you have 2 return value strings (returnValue and retunvalue).
You say your SQL compiles fine, but I get: Must declare the scalar variable "#Password".
Also you are trying to return a varchar (#b) from your stored procedure, but SQL Server stored procedures can only return integers.
When you run the procedure you are going to get the error:
'Conversion failed when converting the varchar value 'x' to data type int.'
There are multiple problems here:
It is not possible. You are trying to return a varchar. Stored
procedure return values can only be integer expressions. See
official RETURN documentation:
https://msdn.microsoft.com/en-us/library/ms174998.aspx.
Your sqlcomm was never executed. You have to call
sqlcomm.ExecuteNonQuery(); in order to execute your command.
Here is a solution using OUTPUT parameters. This was tested with:
Windows Server 2012
.NET v4.0.30319
C# 4.0
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER PROCEDURE [dbo].[Validate]
#a varchar(50),
#b varchar(50) OUTPUT
AS
BEGIN
DECLARE #b AS varchar(50) = (SELECT Password FROM dbo.tblUser WHERE Login = #a)
SELECT #b;
END
SqlConnection SqlConn = ...
var sqlcomm = new SqlCommand("Validate", SqlConn);
string returnValue = string.Empty;
try
{
SqlConn.Open();
sqlcomm.CommandType = CommandType.StoredProcedure;
SqlParameter param = new SqlParameter("#a", SqlDbType.VarChar);
param.Direction = ParameterDirection.Input;
param.Value = Username;
sqlcomm.Parameters.Add(param);
SqlParameter output = sqlcomm.Parameters.Add("#b", SqlDbType.VarChar);
ouput.Direction = ParameterDirection.Output;
sqlcomm.ExecuteNonQuery(); // This line was missing
returnValue = output.Value.ToString();
// ... the rest of code
} catch (SqlException ex) {
throw ex;
}
When we return a value from Stored procedure without select statement.
We need to use "ParameterDirection.ReturnValue" and "ExecuteScalar" command to get the value.
CREATE PROCEDURE IsEmailExists
#Email NVARCHAR(20)
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
-- Insert statements for procedure here
IF EXISTS(SELECT Email FROM Users where Email = #Email)
BEGIN
RETURN 0
END
ELSE
BEGIN
RETURN 1
END
END
in C#
GetOutputParaByCommand("IsEmailExists")
public int GetOutputParaByCommand(string Command)
{
object identity = 0;
try
{
mobj_SqlCommand.CommandText = Command;
SqlParameter SQP = new SqlParameter("returnVal", SqlDbType.Int);
SQP.Direction = ParameterDirection.ReturnValue;
mobj_SqlCommand.Parameters.Add(SQP);
mobj_SqlCommand.Connection = mobj_SqlConnection;
mobj_SqlCommand.ExecuteScalar();
identity = Convert.ToInt32(SQP.Value);
CloseConnection();
}
catch (Exception ex)
{
CloseConnection();
}
return Convert.ToInt32(identity);
}
We get the returned value of SP "IsEmailExists" using above c# function.
This SP looks very strange. It does not modify what is passed to #b. And nowhere in the SP you assign anything to #b. And #Password is not defined, so this SP will not work at all.
I would guess you actually want to return #Password, or to have SET #b = (SELECT...)
Much simpler will be if you modify your SP to (note, no OUTPUT parameter):
set ANSI_NULLS ON set QUOTED_IDENTIFIER ON go
ALTER PROCEDURE [dbo].[Validate] #a varchar(50)
AS
SELECT TOP 1 Password FROM dbo.tblUser WHERE Login = #a
Then, your code can use cmd.ExecuteScalar, and receive the result.
There are two things to fix about this. First set up the stored procedure to store the value in the output ( not return ) parameter.
set ANSI_NULLS ON
set QUOTED_IDENTIFIER ON
go
ALTER PROCEDURE [dbo].[Validate]
#a varchar(50),
#b varchar(50) output
AS
SET #b =
(SELECT Password
FROM dbo.tblUser
WHERE Login = #a)
RETURN
GO
This will but the password into #b and you will get it as a return parameter. Then to get it in your C# do this:
SqlConnection SqlConn = new SqlConnection(System.Configuration.ConfigurationManager.ConnectionStrings["MyLocalSQLServer"].ConnectionString.ToString());
System.Data.SqlClient.SqlCommand sqlcomm = new System.Data.SqlClient.SqlCommand("Validate", SqlConn);
string returnValue = string.Empty;
try
{
SqlConn.Open();
sqlcomm.CommandType = CommandType.StoredProcedure;
SqlParameter param = new SqlParameter("#a", SqlDbType.VarChar, 50);
param.Direction = ParameterDirection.Input;
param.Value = Username;
sqlcomm.Parameters.Add(param);
SqlParameter retval = new SqlParameter("#b", SqlDbType.VarChar, 50);
retval.Direction = ParameterDirection.ReturnValue;
sqlcomm.Parameters.Add(retval);
sqlcomm.ExecuteNonQuery();
SqlConn.Close();
string retunvalue = retval.Value.ToString();
}
May be this will help.
Database script:
USE [edata]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE PROCEDURE [dbo].[InsertNewUser](
#neuname NVARCHAR(255),
#neupassword NVARCHAR(255),
#neuposition NVARCHAR(255)
)
AS
BEGIN
BEGIN TRY
DECLARE #check INT;
SET #check = (SELECT count(eid) FROM eusers WHERE euname = #neuname);
IF(#check = 0)
INSERT INTO eusers(euname,eupassword,eposition)
VALUES(#neuname,#neupassword,#neuposition);
DECLARE #lastid INT;
SET #lastid = ##IDENTITY;
RETURN #lastid;
END TRY
BEGIN CATCH
SELECT ERROR_LINE() as errline,
ERROR_MESSAGE() as errmessage,
ERROR_SEVERITY() as errsevirity
END CATCH
END
Application configuration file:
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<appSettings>
<add key="conStr" value="Data Source=User\SQLEXPRESS;Initial Catalog=edata;Integrated Security=True"/>
</appSettings>
</configuration>
Data Access Layer (DAL):
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Configuration;
using System.Data;
using System.Data.SqlClient;
namespace DAL
{
public static class DAL
{
public static SqlConnection conn;
static DAL()
{
conn = new SqlConnection(ConfigurationManager.AppSettings["conStr"].ToString());
conn.Open();
}
}
}
Business Logic Layer(BLL):
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Data;
using System.Data.SqlClient;
using DAL;
namespace BLL
{
public static class BLL
{
public static int InsertUser(string lastid, params SqlParameter[] coll)
{
int lastInserted = 0;
try
{
SqlCommand comm = new SqlCommand();
comm.Connection = DAL.DAL.conn;
foreach (var param in coll)
{
comm.Parameters.Add(param);
}
SqlParameter lastID = new SqlParameter();
lastID.ParameterName = lastid;
lastID.SqlDbType = SqlDbType.Int;
lastID.Direction = ParameterDirection.ReturnValue;
comm.Parameters.Add(lastID);
comm.CommandType = CommandType.StoredProcedure;
comm.CommandText = "InsertNewUser";
comm.ExecuteNonQuery();
lastInserted = (int)comm.Parameters[lastid].Value;
}
catch (SqlException ex)
{
}
finally {
if (DAL.DAL.conn.State != ConnectionState.Closed) {
DAL.DAL.conn.Close();
}
}
return lastInserted;
}
}
}
Implementation :
BLL.BLL.InsertUser("#lastid",new SqlParameter("neuname","Ded"),
new SqlParameter("neupassword","Moro$ilka"),
new SqlParameter("neuposition","Moroz")
);
You have mixed up the concept of the Return Value and Output variable.
1- Output Variable:
Database----->:
create proc MySP
#a varchar(50),
#b varchar(50) output
AS
SET #Password =
(SELECT Password
FROM dbo.tblUser
WHERE Login = #a)
C# ----->:
SqlConn.Open();
sqlcomm.CommandType = CommandType.StoredProcedure;
SqlParameter param = new SqlParameter("#a", SqlDbType.VarChar);
param.Direction = ParameterDirection.Input;//This is optional because Input is the default
param.Value = Username;
sqlcomm.Parameters.Add(param);
SqlParameter outputval = sqlcomm.Parameters.Add("#b", SqlDbType.VarChar);
outputval .Direction = ParameterDirection.Output//NOT ReturnValue;
string outputvalue = sqlcomm.Parameters["#b"].Value.ToString();
Suppose you need to pass Username and Password to Stored Procedure and know whether login is successful or not and check if any error has occurred in Stored Procedure.
public bool IsLoginSuccess(string userName, string password)
{
try
{
SqlConnection SQLCon = new SqlConnection(WebConfigurationManager.ConnectionStrings["SqlConnector"].ConnectionString);
SqlCommand sqlcomm = new SqlCommand();
SQLCon.Open();
sqlcomm.CommandType = CommandType.StoredProcedure;
sqlcomm.CommandText = "spLoginCheck"; // Stored Procedure name
sqlcomm.Parameters.AddWithValue("#Username", userName); // Input parameters
sqlcomm.Parameters.AddWithValue("#Password", password); // Input parameters
// Your output parameter in Stored Procedure
var returnParam1 = new SqlParameter
{
ParameterName = "#LoginStatus",
Direction = ParameterDirection.Output,
Size = 1
};
sqlcomm.Parameters.Add(returnParam1);
// Your output parameter in Stored Procedure
var returnParam2 = new SqlParameter
{
ParameterName = "#Error",
Direction = ParameterDirection.Output,
Size = 1000
};
sqlcomm.Parameters.Add(returnParam2);
sqlcomm.ExecuteNonQuery();
string error = (string)sqlcomm.Parameters["#Error"].Value;
string retunvalue = (string)sqlcomm.Parameters["#LoginStatus"].Value;
}
catch (Exception ex)
{
}
return false;
}
Your connection string in Web.Config
<connectionStrings>
<add name="SqlConnector"
connectionString="data source=.\SQLEXPRESS;Integrated Security=SSPI;Initial Catalog=Databasename;User id=yourusername;Password=yourpassword"
providerName="System.Data.SqlClient" />
</connectionStrings>
And here is the Stored Procedure for reference
CREATE PROCEDURE spLoginCheck
#Username Varchar(100),
#Password Varchar(100) ,
#LoginStatus char(1) = null output,
#Error Varchar(1000) output
AS
BEGIN
SET NOCOUNT ON;
BEGIN TRY
BEGIN
SET #Error = 'None'
SET #LoginStatus = ''
IF EXISTS(SELECT TOP 1 * FROM EMP_MASTER WHERE EMPNAME=#Username AND EMPPASSWORD=#Password)
BEGIN
SET #LoginStatus='Y'
END
ELSE
BEGIN
SET #LoginStatus='N'
END
END
END TRY
BEGIN CATCH
BEGIN
SET #Error = ERROR_MESSAGE()
END
END CATCH
END
GO
When you use
cmd.Parameters.Add("#RETURN_VALUE", SqlDbType.Int).Direction = ParameterDirection.ReturnValue;
you must then ensure your stored procedure has
return #RETURN_VALUE;
at the end of the stored procedure.
The value you are trying to get is not a return value but an output parameter. You need to change parametere direction to Output.
SqlParameter retval = sqlcomm.Parameters.Add("#b", SqlDbType.VarChar);
retval.Direction = ParameterDirection.Output;
command.ExecuteNonquery();
string retunvalue = (string)sqlcomm.Parameters["#b"].Value;
For .net core 3.0 and dapper:
If your stored procedure returns this:
select ID, FILE_NAME from dbo.FileStorage where ID = (select max(ID) from dbo.FileStorage);
Then in c#:
var data = (_dbConnection.Query<FileUploadQueryResponse>
("dbo.insertFile", whateverParameters, commandType: CommandType.StoredProcedure)).ToList();
var storedFileName = data[0].FILE_NAME;
var id = data[0].ID;
As you can see, you can define a simple class to help with retrieving the actual values from dapper's default return structure (which I found impossible to work with):
public class FileUploadQueryResponse
{
public string ID { get; set; }
public string FILE_NAME { get; set; }
}
This Line of code returns Store StoredProcedure returned value from SQL Server
cmd.Parameters.Add("#id", System.Data.SqlDbType.Int).Direction = System.Data.ParameterDirection.ReturnValue;
cmd.ExecuteNonQuery();
Atfer Execution of query value will returned from SP
id = (int)cmd.Parameters["#id"].Value;