【问题标题】:Getting return value from stored procedure in C#从 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。这段代码有什么逻辑错误?

【问题讨论】:

    标签: c# sql sql-server


    【解决方案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'sMehrdad's 的答案:您永远不会将retval 的参数绑定到sqlcommand。你需要一个

        sqlcomm.Parameters.Add(retval);
        

        并确保您正在运行该命令

        sqlcomm.ExecuteNonQuery();
        

        我也不确定为什么你有 2 个返回值字符串(returnValueretunvalue)。

        【讨论】:

          【解决方案5】:

          你说你的 SQL 编译得很好,但我得到:必须声明标量变量“@Password”。

          您还试图从存储过程中返回一个 varchar (@b),但 SQL Server 存储过程只能返回整数。

          当你运行程序时你会得到错误:

          '将 varchar 值 'x' 转换为数据类型 int 时转换失败。'

          【讨论】:

            【解决方案6】:

            这里有多个问题:

            1. 这是不可能的。您正在尝试返回一个 varchar。已存储 过程返回值只能是整数表达式。看 官方返回文档: https://msdn.microsoft.com/en-us/library/ms174998.aspx
            2. 您的sqlcomm 从未被执行。你必须打电话 sqlcomm.ExecuteNonQuery(); 以执行您的命令。

            这是一个使用 OUTPUT 参数的解决方案。这是通过以下方式测试的:

            • Windows 服务器 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;
            }
            

            【讨论】:

            • 您可能需要将 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】:

                  假设您需要将UsernamePassword传递给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;
                          

                          【讨论】:

                            猜你喜欢
                            • 1970-01-01
                            • 2013-01-22
                            • 1970-01-01
                            • 1970-01-01
                            • 1970-01-01
                            • 1970-01-01
                            • 1970-01-01
                            • 1970-01-01
                            相关资源
                            最近更新 更多