从 C# 中的存储过程中获取返回值
Posted
技术标签:
【中文标题】从 C# 中的存储过程中获取返回值【英文标题】:Getting return value from stored procedure in C# 【发布时间】:2010-10-16 22:07:29 【问题描述】:我有以下疑问:
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
这编译得很好。我想执行这个查询并获取返回值。我的代码如下:
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;
注意:异常处理减少以保持代码简短。每次我到达最后一行时,都会返回 null。这段代码有什么逻辑错误?
【问题讨论】:
【参考方案1】:Mehrdad 提出了一些很好的观点,但我注意到的主要一点是您从不运行查询...
SqlParameter retval = sqlcomm.Parameters.Add("@b", SqlDbType.VarChar);
retval.Direction = ParameterDirection.ReturnValue;
sqlcomm.ExecuteNonQuery(); // MISSING
string retunvalue = (string)sqlcomm.Parameters["@b"].Value;
【讨论】:
在最后一行中,您能否将sqlcomm.Parameters["@b"]
替换为retval
?
你应该试试看。
我不是在问关于我正在编写的代码的问题,我是在努力帮助你为未来的读者改进你的答案。【参考方案2】:
retval.Direction = ParameterDirection.Output;
ParameterDirection.ReturnValue
应该用于过程的“返回值”,而不是输出参数。它获取SQL RETURN
语句返回的值(参数名为@RETURN_VALUE
)。
你应该SET @b = something
而不是RETURN @b
顺便说一句,返回值参数总是int
,而不是字符串。
【讨论】:
【参考方案3】:我在返回值方面遇到了很多麻烦,所以最后我只是选择了一些东西。
解决办法就是在最后选择结果,然后在你的函数中返回查询结果。
在我的情况下,我正在执行存在检查:
IF (EXISTS (SELECT RoleName FROM dbo.Roles WHERE @RoleName = RoleName))
SELECT 1
ELSE
SELECT 0
然后
using (SqlConnection cnn = new SqlConnection(ConnectionString))
SqlCommand cmd = cnn.CreateCommand();
cmd.CommandType = CommandType.StoredProcedure;
cmd.CommandText = "RoleExists";
return (int) cmd.ExecuteScalar()
你应该能够用字符串值而不是 int 来做同样的事情。
【讨论】:
【参考方案4】:这是基于Joel's 和Mehrdad's 的答案:您永远不会将retval
的参数绑定到sqlcommand
。你需要一个
sqlcomm.Parameters.Add(retval);
并确保您正在运行该命令
sqlcomm.ExecuteNonQuery();
我也不确定为什么你有 2 个返回值字符串(returnValue
和 retunvalue
)。
【讨论】:
【参考方案5】:你说你的 SQL 编译得很好,但我得到:必须声明标量变量“@Password”。
您还试图从存储过程中返回一个 varchar (@b),但 SQL Server 存储过程只能返回整数。
当你运行程序时你会得到错误:
'将 varchar 值 'x' 转换为数据类型 int 时转换失败。'
【讨论】:
【参考方案6】:这里有多个问题:
-
这是不可能的。您正在尝试返回一个 varchar。已存储
过程返回值只能是整数表达式。看
官方返回文档:
https://msdn.microsoft.com/en-us/library/ms174998.aspx。
您的
sqlcomm
从未被执行。你必须打电话
sqlcomm.ExecuteNonQuery();
以执行您的命令。
这是一个使用 OUTPUT 参数的解决方案。这是通过以下方式测试的:
Windows 服务器 2012 .NET v4.0.30319 C# 4.0SET 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;
【讨论】:
您可能需要将 varchar 的长度添加为sqlcomm.Parameters.Add("@b", SqlDbType.VarChar,50);
这里 50 是长度。【参考方案7】:
当我们从没有选择语句的存储过程中返回一个值时。 我们需要使用“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
在 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);
我们使用上面的c#函数得到SP“IsEmailExists”的返回值。
【讨论】:
【参考方案8】:这个SP看起来很奇怪。它不会修改传递给@b 的内容。在 SP 中没有任何地方可以为 @b 分配任何东西。而且@Password 没有定义,所以这个SP 根本不起作用。
我猜你实际上想返回@Password,或者让 SET @b = (SELECT...)
如果您将 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
然后,您的代码可以使用 cmd.ExecuteScalar,并接收结果。
【讨论】:
【参考方案9】:对此有两点需要解决。首先设置存储过程将值存储在输出(而不是返回)参数中。
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
这会将密码输入@b,您将获得它作为返回参数。然后在你的 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();
【讨论】:
我觉得应该是"retval.Direction = ParameterDirection.Output"【参考方案10】:也许这会有所帮助。
数据库脚本:
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
应用配置文件:
<?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>
数据访问层 (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();
业务逻辑层(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;
实施:
BLL.BLL.InsertUser("@lastid",new SqlParameter("neuname","Ded"),
new SqlParameter("neupassword","Moro$ilka"),
new SqlParameter("neuposition","Moroz")
);
【讨论】:
【参考方案11】:您混淆了返回值和输出变量的概念。 1- 输出变量:
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();
【讨论】:
我喜欢这个,但似乎“SET @Password”应该是“SET @b”【参考方案12】:假设您需要将Username
和Password
传递给Stored Procedure,并知道登录是否成功并检查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;
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>
这里是存储过程供参考
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
【讨论】:
【参考方案13】:当你使用时
cmd.Parameters.Add("@RETURN_VALUE", SqlDbType.Int).Direction = ParameterDirection.ReturnValue;
你必须确保你的存储过程有
return @RETURN_VALUE;
在存储过程结束时。
【讨论】:
【参考方案14】:您尝试获取的值不是返回值,而是输出参数。您需要将参数方向更改为输出。
SqlParameter retval = sqlcomm.Parameters.Add("@b", SqlDbType.VarChar);
retval.Direction = ParameterDirection.Output;
command.ExecuteNonquery();
string retunvalue = (string)sqlcomm.Parameters["@b"].Value;
【讨论】:
【参考方案15】:对于 .net core 3.0 和 dapper:
如果你的存储过程返回这个:
select ID, FILE_NAME from dbo.FileStorage where ID = (select max(ID) from dbo.FileStorage);
然后在c#中:
var data = (_dbConnection.Query<FileUploadQueryResponse>
("dbo.insertFile", whateverParameters, commandType: CommandType.StoredProcedure)).ToList();
var storedFileName = data[0].FILE_NAME;
var id = data[0].ID;
如您所见,您可以定义一个简单的类来帮助从 dapper 的默认返回结构(我发现无法使用)中检索实际值:
public class FileUploadQueryResponse
public string ID get; set;
public string FILE_NAME get; set;
【讨论】:
【参考方案16】:这行代码从 SQL Server 返回 Store StoredProcedure 返回值
cmd.Parameters.Add("@id", System.Data.SqlDbType.Int).Direction = System.Data.ParameterDirection.ReturnValue;
cmd.ExecuteNonQuery();
Atfer 执行的查询值将从 SP 返回
id = (int)cmd.Parameters["@id"].Value;
【讨论】:
以上是关于从 C# 中的存储过程中获取返回值的主要内容,如果未能解决你的问题,请参考以下文章
Asp.net(C#) 获取 执行sql server 语句/存储过程后的 多个返回值?
C#获取存储过程的 Return返回值和Output输出参数值