从C#中的存储过程获取返回值
我有以下查询:
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
这个编译非常好。
在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); 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;
注:exception处理剪切,以保持代码简短。 每当我到达最后一行,返回null。 这段代码的逻辑错误是什么?
谢谢
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
应该用于过程的“返回值”,而不是输出参数。 它获取由SQL RETURN
语句返回的值(带有名为@RETURN_VALUE
的参数)。
而不是RETURN @b
你应该SET @b = something
顺便说一句,返回值参数总是int
,而不是string。
我在回报价值方面遇到了很多麻烦,所以最后我只是select了一些东西。
解决scheme只是在最后select结果,并返回查询结果在您的functinon。
在我的情况下,我正在做一个存在检查:
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() }
你应该可以用一个string值而不是int来做同样的事情。
这是build立在Joel和Mehrdad的答案上的:你永远不会把retval
的参数绑定到sqlcommand
。 你需要一个
sqlcomm.Parameters.Add(retval);
并确保您正在运行该命令
sqlcomm.ExecuteNonQuery();
我也不确定为什么你有2个返回值string( returnValue
和retunvalue
)。
你说你的SQL编译好,但我得到:必须声明标量variables“@Password”。
你也试图从存储过程中返回一个varchar(@b),但是SQL Server存储过程只能返回整数。
当你运行这个程序时,你将会得到这个错误:
将varchar值“x”转换为数据typesint时转换失败
这个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,并接收结果。
这里有很多问题:
- 这不可能。 你正试图返回一个varchar。 存储过程返回值只能是整数expression式。 请参阅官方RETURN文档: https : //msdn.microsoft.com/en-us/library/ms174998.aspx 。
- 你的
sqlcomm
从未执行过。 你必须调用sqlcomm.ExecuteNonQuery();
为了执行你的命令。
这是一个使用OUTPUT参数的解决scheme。 这已经过testing:
- 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; }
你已经混淆了返回值和输出variables的概念。 1-输出variables:
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 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(); }
可能会有所帮助。
数据库脚本:
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
应用程序configuration文件
<?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") );
当你使用
cmd.Parameters.Add("@RETURN_VALUE", SqlDbType.Int).Direction = ParameterDirection.ReturnValue;
你必须确保你的存储过程
return @RETURN_VALUE;
在存储过程的末尾。
假设您需要将Username
和Password
传递给存储过程,并知道login是否成功,并检查存储过程是否发生错误。
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
连接string
<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