I need to insert a line in my question table and retrieve the inserted id. I initialize my sql command and execute it with ExecuteScalar(). I'm trying to convert the result of this method to int but I can not do it.
I tried to do that:
int result = Convert.ToInt32(Command.ExecuteScalar));
or
int result = (int)Command.ExecuteScalar();
but nothing work
here is my function
public int AddQuestionOrientation(Question questionForAdd)
{
try
{
con = new SqlConnection(connectionString);
con.Open();
SqlCommand command;
String sql = "";
sql = "INSERT INTO QUESTION VALUES(#Libelle,
#Bareme,2,#Filliere)";
SqlParameter param = new SqlParameter();
param.ParameterName = "#Libelle";
param.Value = questionForAdd.Libelle;
SqlParameter param2 = new SqlParameter();
param2.ParameterName = "#Bareme";
param2.Value = questionForAdd.Bareme;
SqlParameter param3 = new SqlParameter();
param3.ParameterName = "#Filliere";
param3.Value = questionForAdd.IdFiliere;
command = new SqlCommand(sql, con);
command.Parameters.Add(param);
command.Parameters.Add(param2);
command.Parameters.Add(param3);
int idQuestionInserted = (int)command.ExecuteScalar();
command.Dispose();
con.Close();
return idQuestionInserted;
}
catch(Exception ex)
{
return 0;
}
}
If I try with the cast (int), I have the message error:
Object reference not set to an instance of an object
If I try with the Convert.ToInt32, my variable "IdQuestionInserted" is equal to 0.
This is a big departure from where you started. But you have several issue going on there. You should use the USING statement around objects with the IDisposable interface (connections, commands, etc...).
This code is all untested but should be really close.
Start with creating a stored procedure so you can start creating layers in your application.
create Procedure Question_Insert
(
#Libelle varchar(50)
, #Bareme varchar(50)
, #Filliere varchar(50)
, #QuestionID int output
) as
set nocount on;
INSERT INTO QUESTION
(
Libelle
, Bareme
, Filliere
)
values
(
#Libelle
, #Bareme
, #Filliere
)
select #QuestionID = SCOPE_IDENTITY()
Then in your dotnet code you need to change up a few things to make it cleaner and more robust. Ideally you should do something better than simply return 0 when there is an error. It will be really tough to debug when something goes wrong if you simply return a 0. This is like an error message that says, "An error occurred". Pretty useless. Do something with the error. Capture the message to enable you to fix it.
public int AddQuestionOrientation(Question questionForAdd)
{
try
{
using (SqlConnection con = new SqlConnection(connectionString))
{
con.Open();
using (SqlCommand command = new SqlCommand("Question_Insert"))
{
command.CommandType = CommandType.StoredProcedure;
command.Parameters.Add("#Libelle", SqlDbType.VarChar, 50).Value = questionForAdd.Libelle;
command.Parameters.Add("#Bareme", SqlDbType.VarChar, 50).Value = questionForAdd.Bareme;
command.Parameters.Add("#Filliere", SqlDbType.VarChar, 50).Value = questionForAdd.IdFiliere;
command.Parameters.Add("#QuestionID", SqlDbType.Int).Direction = ParameterDirection.Output;
command.ExecuteNonQuery();
return int.Parse(command.Parameters["#QuestionID"].Value.ToString());
}
}
}
catch (Exception ex)
{
return 0;
}
}
To get inserted id use SCOPE_IDENTITY() add SELECT CAST(scope_identity() AS int to command query to do
INSERT INTO QUESTION
VALUES(#Libelle, #Bareme, 2, #Filliere);
SELECT CAST(scope_identity() AS int;
this query will return inserted id for you.
Related
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 am coding winform application where i call procedure in my datagrid.
I have method where I define parameters of procedure
public int Add_Nastavenie(out int typNastav, int nastavID, string hod)
{
ResetParameters();
cmd.CommandText = "add_Nastav";
cmd.CommandType = CommandType.StoredProcedure;
SqlParameter sqlParameter;
var sqlParameterOut = new SqlParameter("#TypNastav", SqlDbType.Int);
sqlParameterOut.Direction = ParameterDirection.Output;
sqlParameter = new SqlParameter("#NastavenieID", SqlDbType.Int);
sqlParameter.Direction = ParameterDirection.Input;
sqlParameter.Value = nastavID;
cmd.Parameters.Add(sqlParameter);
sqlParameter = new SqlParameter("#Hodnota", SqlDbType.NVarChar, 100);
sqlParameter.Direction = ParameterDirection.Input;
sqlParameter.Value = hod;
cmd.Parameters.Add(sqlParameter);
var sqlParameterRet = new SqlParameter("retValue", SqlDbType.Int);
sqlParameterRet.Direction = ParameterDirection.ReturnValue;
cmd.ExecuteNonQuery();
typNastav = (int)sqlParameterOut.Value;
return (int)cmd.Parameters["retvalue"].Value;
}
then i call procedure this way
dataConnector.Add_Nastavenie(typNastav,nastavID,hod);
I have an error Argument 1 must be passed with the 'out' keyword
I change it to dataConnector.Add_Nastavenie(out typNastav,nastavID,hod);
error dissapear but application is not working, procedure do nothing .
My try catch exception show : Procedure or function 'add_Nastav' expects parameter '#TypNastav', which was not supplied.
Can somebody help find solution ? Thanks .
You haven't added the OUTPUT parameter the stored procedure is expecting:
cmd.Parameters.Add(sqlParameterOut);
Example:
SqlCommand com = new SqlCommand("update_outptu_Stock", connect.con);
com.CommandType = CommandType.StoredProcedure;
com.Parameters.AddWithValue("#cg_id ", 1);
SqlParameter par = new SqlParameter("#id", SqlDbType.Int)
{
Direction = ParameterDirection.Output
};
SQL:
Create proc update_outptu_Stock
#cg_id int,
#id int output
as
begin
insert into example(cg_id) values (#cg_id)
set #id = SCOPE_IDENTITY() -- get value of id created
end
Go
Get parameter id:
var parvalue = id.value;
i have a stored procedure
ALTER PROC TESTLOGIN
#UserName varchar(50),
#password varchar(50)
As
Begin
declare #return int;
set #return = (SELECT COUNT(*)
FROM CPUser
WHERE UserName = #UserName
AND Password = #password);
return #return;
End
and in c#
SqlConnection con = db.con;
SqlCommand cmd = new SqlCommand("TESTLOGIN", con);
cmd.CommandType = CommandType.StoredProcedure;
SqlParameter parm = new SqlParameter("#return", SqlDbType.Int);
parm.Direction = ParameterDirection.ReturnValue;
cmd.Parameters.Add(parm);
cmd.Parameters.Add(new SqlParameter("#UserName", txtUserName.Text.ToString().Trim()));
cmd.Parameters.Add(new SqlParameter("#password", txtPassword.Text.ToString().Trim()));
cmd.ExecuteNonQuery();
con.Close();
int id = Convert.ToInt32(parm.Value);
but it always return 0. Please help me to solve this problem
You need a parameter with Direction set to ParameterDirection.ReturnValue in code but no need to add an extra parameter in SP. Try this
SqlParameter returnParameter = cmd.Parameters.Add("RetVal", SqlDbType.Int);
returnParameter.Direction = ParameterDirection.ReturnValue;
cmd.ExecuteNonQuery();
int id = (int) returnParameter.Value;
2 things.
The query has to complete on sql server before the return value is sent.
The results have to be captured and then finish executing before
the return value gets to the object.
In English, finish the work and then retrieve the value.
this will not work:
cmm.ExecuteReader();
int i = (int) cmm.Parameters["#RETURN_VALUE"].Value;
This will work:
SqlDataReader reader = cmm.ExecuteReader();
reader.Close();
foreach (SqlParameter prm in cmd.Parameters)
{
Debug.WriteLine("");
Debug.WriteLine("Name " + prm.ParameterName);
Debug.WriteLine("Type " + prm.SqlDbType.ToString());
Debug.WriteLine("Size " + prm.Size.ToString());
Debug.WriteLine("Direction " + prm.Direction.ToString());
Debug.WriteLine("Value " + prm.Value);
}
if you are not sure
check the value of the parameter
before during and after the results have been processed by the reader.
you can try this.Add the parameter as output direction and after executing the query get the output parameter value.
SqlParameter parmOUT = new SqlParameter("#return", SqlDbType.Int);
parmOUT.Direction = ParameterDirection.Output;
cmd.Parameters.Add(parmOUT);
cmd.ExecuteNonQuery();
int returnVALUE = (int)cmd.Parameters["#return"].Value;
Procedure never returns a value.You have to use a output parameter in store procedure.
ALTER PROC TESTLOGIN
#UserName varchar(50),
#password varchar(50)
#retvalue int output
as
Begin
declare #return int
set #return = (Select COUNT(*)
FROM CPUser
WHERE UserName = #UserName AND Password = #password)
set #retvalue=#return
End
Then you have to add a sqlparameter from c# whose parameter direction is out.
Hope this make sense.
If you want to to know how to return a value from stored procedure to Visual Basic.NET. Please read this tutorial: How to return a value from stored procedure
I used the following stored procedure to return the value.
CREATE PROCEDURE usp_get_count
AS
BEGIN
DECLARE #VALUE int;
SET #VALUE=(SELECT COUNT(*) FROM tblCar);
RETURN #VALUE;
END
GO
Do it this way (make necessary changes in code)..
SqlConnection con = new SqlConnection(GetConnectionString());
con.Open();
SqlCommand cmd = new SqlCommand("CheckUser", con);
cmd.CommandType = CommandType.StoredProcedure;
SqlParameter p1 = new SqlParameter("username", username.Text);
SqlParameter p2 = new SqlParameter("password", password.Text);
cmd.Parameters.Add(p1);
cmd.Parameters.Add(p2);
SqlDataReader rd = cmd.ExecuteReader();
if(rd.HasRows)
{
//do the things
}
else
{
lblinfo.Text = "abc";
}
In the below Stored procedure, i am returning a row if all the conditions satisfies, orelse i am returning a message like which condition is nor satisfied.
The Stored proc is working perfectly...
ALTER PROCEDURE dbo.BookingCheck
(
#int_duration_of_stay int ,
#int_number_of_guests int,
#date_of_application date,
#date_of_checkin date,
#date_of_checkout date,
#str_room_type varchar(50),
#ret_value varchar(100) = '' output
)
AS
DECLARE #MaxPer int
DECLARE #BasicCharge int
DECLARE #SurCharge int
DECLARE #TotalAmount int
DECLARE #NoOfDays int
DECLARE #Free VARCHAR(10)
IF #int_duration_of_stay > 6
BEGIN
SET #NoOfDays = #int_duration_of_stay
SET #Free = 'Yes'
END
ELSE
BEGIN
SET #NoOfDays = #int_duration_of_stay - 1
SET #Free = 'No'
END
SELECT #MaxPer = int_max_pax, #BasicCharge = flt_basic_charge, #SurCharge = flt_surcharge_per_pax
FROM RoomTypes WHERE UPPER(str_room_type) = UPPER(#str_room_type)
IF DATEDIFF(DAY, GETDATE(), #date_of_checkin) < 40
BEGIN
IF #int_number_of_guests <= #MaxPer
BEGIN
SET #TotalAmount = (#NoOfDays * #int_number_of_guests * #SurCharge) + #BasicCharge
SET #ret_value = 'Success'
SELECT #str_room_type as 'Room Type', #MaxPer as 'Max Persons Allowed', #int_number_of_guests as 'No. of persons requested',
#int_duration_of_stay as 'No. of days stay', #BasicCharge as 'Basic Charge', #SurCharge as 'Sur Charge', #Free as 'Complimentary',
#TotalAmount as 'Total Amount'
END
ELSE
BEGIN
SET #ret_value = 'Max persons allowed is ' + CONVERT(VARCHAR(20), #MaxPer)
END
END
ELSE
BEGIN
SET #ret_value = 'The check in date should be less than 40 days from current date.'
END
RETURN
The problem is dont know how to get the return message or return row from the SP using c#.
The below code returns me the rows if the condition is satisfied in SP. if not, i am not getting the return message. How to get that ?
public DataSet BookingCheck(int duration_of_stay, int number_of_guests,
string date_of_application, string date_of_checkin, string date_of_checkout,
string room_type)
{
DataSet dsGetBookingCheck = new DataSet();
SqlConnection conn = new SqlConnection(Con);
SqlCommand command = new SqlCommand("BookingCheck", conn);
command.CommandType = CommandType.StoredProcedure;
SqlDataAdapter da = new SqlDataAdapter();
SqlParameter param = new SqlParameter();
param = command.Parameters.Add("#int_duration_of_stay", SqlDbType.Int);
param.Value = duration_of_stay;
param = command.Parameters.Add("#int_number_of_guests", SqlDbType.Int);
param.Value = number_of_guests;
param = command.Parameters.Add("#date_of_application", SqlDbType.Date);
param.Value = date_of_application;
param = command.Parameters.Add("#date_of_checkin", SqlDbType.Date);
param.Value = date_of_checkin;
param = command.Parameters.Add("#date_of_checkout", SqlDbType.Date);
param.Value = date_of_checkout;
param = command.Parameters.Add("#str_room_type", SqlDbType.VarChar, 50);
param.Value = room_type;
conn.Open();
command.ExecuteNonQuery();
da.SelectCommand = command;
da.Fill(dsGetBookingCheck);
conn.Close();
return dsGetBookingCheck;
}
You need to add an out parameter:
command.Parameters.Add("#ret_value", SqlDbType.String);
command.Parameters["#ret_value"].Direction = ParameterDirection.Output;
then after executing the SP
message = command.Parameters["#ret_value"].Value.ToString();
Here is function with out param:
public DataSet BookingCheck(int duration_of_stay, int number_of_guests,
string date_of_application, string date_of_checkin, string date_of_checkout,
string room_type, out string message)
{
DataSet dsGetBookingCheck = new DataSet();
SqlConnection conn = new SqlConnection(Con);
SqlCommand command = new SqlCommand("BookingCheck", conn);
command.CommandType = CommandType.StoredProcedure;
SqlDataAdapter da = new SqlDataAdapter();
SqlParameter param = new SqlParameter();
param = command.Parameters.Add("#int_duration_of_stay", SqlDbType.Int);
param.Value = duration_of_stay;
param = command.Parameters.Add("#int_number_of_guests", SqlDbType.Int);
param.Value = number_of_guests;
param = command.Parameters.Add("#date_of_application", SqlDbType.Date);
param.Value = date_of_application;
param = command.Parameters.Add("#date_of_checkin", SqlDbType.Date);
param.Value = date_of_checkin;
param = command.Parameters.Add("#date_of_checkout", SqlDbType.Date);
param.Value = date_of_checkout;
param = command.Parameters.Add("#str_room_type", SqlDbType.VarChar, 50);
param.Value = room_type;
command.Parameters.Add("#ret_value", SqlDbType.String);
command.Parameters["#ret_value"].Direction = ParameterDirection.Output;
conn.Open();
command.ExecuteNonQuery();
da.SelectCommand = command;
da.Fill(dsGetBookingCheck);
message = command.Parameters["#ret_value"].Value.ToString();
conn.Close();
return dsGetBookingCheck;
}
NOTE: I have never done with with using ExecuteNonQuery and then using Fill on a data adapter. That might mess this up.
What is ExecuteNonQuery doing in your code when you are not inserting anything?
There are ways to do this. One, use a DataReader. It is a bit more helpful in these kind of scenarios. Or you can add a output parameter to the stored procedure and check that after you execute the proc through C#.
That's not doable in C#. You can only either return a DataTable with a single row (using the Fill method in your example) or you can return a single value (using an SqlCommand with a return parameter or ExecuteScalar).
Instead you should do a SELECT in both cases but with different fields depending on the IF statement. I.e.,
SET #ret_value = 'Max persons allowed is ' + CONVERT(VARCHAR(20), #MaxPer)
is converted to be
SELECT 'Max persons allowed is ' + CONVERT(VARCHAR(20), #MaxPer) AS Return_Value
And then you check for the field name in your return DataTable. E.g.
if (BookingCheck(...).Tables[0].Columns.Contains("Return_Value")) {
// Handle my special condition here
}
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;