[英]Getting return value from stored procedure in C#
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.每次我到达最后一行时,都会返回 null。 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 ... Mehrdad 提出了一些很好的观点,但我注意到的主要一点是你从不运行查询......
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. ParameterDirection.ReturnValue
应该用于程序的“返回值”,而不是 output 参数。 It gets the value returned by the SQL RETURN
statement (with the parameter named @RETURN_VALUE
).它获取 SQL RETURN
语句返回的值(参数名为@RETURN_VALUE
)。
Instead of RETURN @b
you should SET @b = something
而不是RETURN @b
你应该SET @b = something
By the way, return value parameter is always int
, not string.顺便说一句,返回值参数始终是int
,而不是 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.解决方案只是 select 最后的结果并在您的函数中返回查询结果。
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.您应该能够使用字符串值而不是 int 来做同样的事情。
This is building on Joel's and Mehrdad's answers: you're never binding the parameter of the retval
to the sqlcommand
.这是建立在Joel和Mehrdad 的答案之上的:您永远不会将retval
的参数绑定到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
).我也不确定为什么你有 2 个返回值字符串( returnValue
和retunvalue
)。
There are multiple problems here:这里有多个问题:
sqlcomm
was never executed.您的sqlcomm
从未执行过。 You have to call sqlcomm.ExecuteNonQuery();
你必须调用sqlcomm.ExecuteNonQuery();
in order to execute your command.为了执行你的命令。Here is a solution using OUTPUT parameters.这是使用 OUTPUT 参数的解决方案。 This was tested with:对此进行了测试:
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.当我们从没有 select 语句的存储过程中返回一个值时。 We need to use "ParameterDirection.ReturnValue" and "ExecuteScalar" command to get the value.我们需要使用“ParameterDirection.ReturnValue”和“ExecuteScalar”命令来获取值。
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#在 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.我们使用上面的 c# function 得到 SP "IsEmailExists" 的返回值。
You say your SQL compiles fine, but I get: Must declare the scalar variable "@Password".你说你的 SQL 编译得很好,但我得到:必须声明标量变量“@Password”。
Also you are trying to return a varchar (@b) from your stored procedure, but SQL Server stored procedures can only return integers.您还试图从存储过程中返回一个 varchar (@b),但 SQL 服务器存储过程只能返回整数。
When you run the procedure you are going to get the error:当您运行该过程时,您将收到错误:
'Conversion failed when converting the varchar value 'x' to data type int.' '将 varchar 值 'x' 转换为数据类型 int 时转换失败。'
There are two things to fix about this.有两件事要解决这个问题。 First set up the stored procedure to store the value in the output ( not return ) parameter.首先设置存储过程存储output(不返回)参数中的值。
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.这会将密码输入@b,您将获得它作为返回参数。 Then to get it in your C# do this:然后将其放入您的 C# 中,请执行以下操作:
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):数据访问层 (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):业务逻辑层(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")
);
This SP looks very strange.这个SP看起来很奇怪。 It does not modify what is passed to @b.它不会修改传递给@b 的内容。 And nowhere in the SP you assign anything to @b.在 SP 中没有任何地方可以为 @b 分配任何东西。 And @Password is not defined, so this SP will not work at all.并且@Password 没有定义,所以这个SP 根本不起作用。
I would guess you actually want to return @Password, or to have SET @b = (SELECT...)我猜你实际上想要返回@Password,或者让 SET @b = (SELECT...)
Much simpler will be if you modify your SP to (note, no OUTPUT parameter):如果您将 SP 修改为(注意,没有 OUTPUT 参数),则简单得多:
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.然后,您的代码可以使用 cmd.ExecuteScalar,并接收结果。
You have mixed up the concept of the Return Value and Output variable.您混淆了 Return Value 和 Output 变量的概念。 1- Output Variable: 1- Output 变量:
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 .假设您需要将Username
和Password
传递给存储过程,并知道登录是否成功,并检查存储过程中是否发生任何错误。
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
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.您尝试获取的值不是返回值,而是 output 参数。 You need to change parametere direction to Output.您需要将参数方向更改为 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:对于 .net 核心 3.0 和 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#:然后在 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):如您所见,您可以定义一个简单的 class 来帮助从 dapper 的默认返回结构(我发现无法使用)中检索实际值:
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这行代码从 SQL 服务器返回 Store StoredProcedure 返回值
cmd.Parameters.Add("@id", System.Data.SqlDbType.Int).Direction = System.Data.ParameterDirection.ReturnValue;
cmd.ExecuteNonQuery();
Atfer Execution of query value will returned from SP Atfer 执行查询值将从 SP 返回
id = (int)cmd.Parameters["@id"].Value;
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.