从C#中的存储过程获取返回值

时间:2009-04-01 16:31:56

标签: c# sql sql-server

我有以下查询:

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;

注意:切断异常处理以保持代码简短。每当我到达最后一行时,返回null。这段代码的逻辑错误是什么?

由于

16 个答案:

答案 0 :(得分:85)

Mehrdad提出了一些好处,但我注意到的主要事情是你永远不会运行查询 ......

SqlParameter retval = sqlcomm.Parameters.Add("@b", SqlDbType.VarChar);
retval.Direction = ParameterDirection.ReturnValue;
sqlcomm.ExecuteNonQuery(); // MISSING
string retunvalue = (string)sqlcomm.Parameters["@b"].Value;

答案 1 :(得分:61)

retval.Direction = ParameterDirection.Output;

ParameterDirection.ReturnValue应该用于过程的“返回值”,而不是输出参数。它获取SQL RETURN语句返回的值(使用名为@RETURN_VALUE的参数)。

而不是RETURN @b你应该SET @b = something

顺便说一句,返回值参数始终是int,而不是字符串。

答案 2 :(得分:10)

我在返回值方面遇到了很多麻烦,所以我最后只是选择了一些东西。

解决方案只是在结尾处选择结果并在您的功能中返回查询结果。

在我的情况下,我正在进行存在检查:

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来执行相同的操作。

答案 3 :(得分:5)

这是基于Joel'sMehrdad's答案:您永远不会将retval的参数绑定到sqlcommand。你需要一个

sqlcomm.Parameters.Add(retval);

并确保您正在运行命令

sqlcomm.ExecuteNonQuery();

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

答案 4 :(得分:4)

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

此外,您尝试从存储过程返回varchar(@b),但SQL Server存储过程只能返回整数。

当您运行该过程时,您将收到错误:

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

答案 5 :(得分:3)

这个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,并接收结果。

答案 6 :(得分:3)

这里有很多问题:

  1. 这是不可能的。您正在尝试返回varchar。存储 过程返回值只能是整数表达式。看到 官方RETURN文件: https://msdn.microsoft.com/en-us/library/ms174998.aspx
  2. 您的sqlcomm从未执行过。你必须打电话 sqlcomm.ExecuteNonQuery();以执行您的命令。
  3. 这是使用OUTPUT参数的解决方案。测试结果如下:

    • 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;
    }
    

答案 7 :(得分:3)

可能会有所帮助。

数据库脚本:

<?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>

应用程序配置文件:

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();


        }


    }
}

数据访问层(DAL):

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.BLL.InsertUser("@lastid",new SqlParameter("neuname","Ded"),
                 new SqlParameter("neupassword","Moro$ilka"),
                 new SqlParameter("neuposition","Moroz")
                 );

实施:

=SUMIF('Daily Expense'!A:A,CONCATENATE("2/",B1,"/2017"),'Daily Expense'!B:B)

答案 8 :(得分:3)

当我们从没有select语句的存储过程返回值时。 我们需要使用“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”的返回值。

答案 9 :(得分:2)

你混淆了Return Value和Output变量的概念。 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();

答案 10 :(得分:2)

有两件事需要解决。首先设置存储过程以将值存储在输出(不返回)参数中。

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();
     }

答案 11 :(得分:1)

使用时

C:\Ruby193\bin\scss.bat

然后您必须确保您的存储过程

cmd.Parameters.Add("@RETURN_VALUE", SqlDbType.Int).Direction = ParameterDirection.ReturnValue;

在存储过程结束时。

答案 12 :(得分:0)

假设您需要将UsernamePassword传递给存储过程,并知道登录是否成功,并检查存储过程中是否发生错误

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 :(得分:0)

您尝试获取的值不是返回值,而是输出参数。您需要将参数方向更改为“输出”。

SqlParameter retval = sqlcomm.Parameters.Add("@b", SqlDbType.VarChar);
retval.Direction = ParameterDirection.Output;
command.ExecuteNonquery();
string retunvalue = (string)sqlcomm.Parameters["@b"].Value;

答案 14 :(得分:0)

对于.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; }
  }

答案 15 :(得分:-1)

此行代码从SQL Server返回Store StoredProcedure返回的值

cmd.Parameters.Add("@id", System.Data.SqlDbType.Int).Direction = System.Data.ParameterDirection.ReturnValue;                
cmd.ExecuteNonQuery();

查询值的执行将从SP返回

id = (int)cmd.Parameters["@id"].Value;