2009-04-01 30 views
57

Tengo la siguiente consulta:Obtener valor de retorno de procedimiento almacenado en 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 

Esto compila perfectamente bien.

En C#, deseo ejecutar esta consulta y obtener el valor de retorno.

Mi código es la siguiente:

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; 

Nota: la gestión de excepciones corte para mantener el código corto. Cada vez que llego a la última línea, se devuelve null. ¿Cuál es el error de lógica con este código?

Gracias

Respuesta

59
retval.Direction = ParameterDirection.Output; 

ParameterDirection.ReturnValue deben utilizarse para el "valor de retorno" del procedimiento, no los parámetros de salida. Obtiene el valor devuelto por la instrucción SQL RETURN (con el parámetro denominado @RETURN_VALUE).

En lugar de RETURN @b que debiera SET @b = something

Por cierto, el parámetro de valor de retorno es siempre int, no cadena.

82

Mehrdad hace algunos buenos puntos, pero lo más importante que he notado es que nunca se ejecuta la consulta ...

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

Usted dice que su SQL compila bien, pero me da: Debe declarar el escalar variable "@ Contraseña".

También intenta devolver un varchar (@b) desde su procedimiento almacenado, pero los procedimientos almacenados de SQL Server solo pueden devolver enteros.

Cuando se ejecuta el procedimiento que se va a obtener el error:

'Error de conversión al convertir el valor varchar 'x' al tipo de datos int.'

3

Este SP se ve muy extraño. No modifica lo que se pasa a @b. Y en ninguna parte del SP asigna algo a @b. Y @Password no está definido, por lo que este SP no funcionará en absoluto.

yo supongo que realmente desea volver @Password, o haber SET @b = (SELECT ...)

Mucho más simple será si modifica el SP a (nota, sin parámetro 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 

Luego, su código puede usar cmd.ExecuteScalar y recibirá el resultado.

8

Estaba teniendo un montón de problemas con el valor de retorno, así que terminé simplemente seleccionando cosas al final.

La solución fue simplemente seleccionar el resultado al final y devolver el resultado de la consulta en su función.

En mi caso yo estaba haciendo una existe comprobar:

IF (EXISTS (SELECT RoleName FROM dbo.Roles WHERE @RoleName = RoleName)) 
    SELECT 1 
ELSE 
    SELECT 0 

Entonces

using (SqlConnection cnn = new SqlConnection(ConnectionString)) 
{ 
    SqlCommand cmd = cnn.CreateCommand(); 
    cmd.CommandType = CommandType.StoredProcedure; 
    cmd.CommandText = "RoleExists"; 
    return (int) cmd.ExecuteScalar() 
} 

usted debería ser capaz de hacer lo mismo con un valor de cadena en lugar de un int.

+0

me es muy útil.Gracias –

5

Esta es la construcción de Joel's y Mehrdad's respuestas: usted nunca vinculante el parámetro de la retval a la sqlcommand. Se necesita una

sqlcomm.Parameters.Add(retval); 

y para asegurarse de que está ejecutando el comando

sqlcomm.ExecuteNonQuery(); 

Tampoco estoy seguro de por qué usted tiene 2 cadenas de valor de retorno (returnValue y retunvalue).

2

Ha confundido el concepto de la variable Valor devuelto y Salida. variable 1- Salida:

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

Me gusta esto pero parece que "SET @Password" debería ser "SET @b" –

0

Supongamos que necesita para pasar Username y Password a procedimiento almacenado y saber si inicia la sesión correctamente o no, y comprobar si se ha producido algún error en procedimiento almacenado.

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

Su cadena de conexión en 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> 

Y aquí es el procedimiento almacenado para referencia

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 [email protected] AND [email protected]) 
      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 
2

Hay dos cosas que arreglar esto. Primero configure el procedimiento almacenado para almacenar el valor en el parámetro de salida (no retorno).

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 

Esto solo enviará la contraseña a @b y la obtendrá como un parámetro de retorno. A continuación, para conseguir que en su C# hacer esto:

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

Esto debería estar en la parte superior. ¡La única respuesta verdaderamente completa! – Seth

1

cuando se utiliza

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

a continuación, debe asegurarse de que su procedimiento almacenado tiene

return @RETURN_VALUE; 

al final del procedimiento almacenado.

3

hay varios problemas aquí:

  1. No es posible. Estás tratando de devolver un varchar. Los valores de retorno del procedimiento almacenados solo pueden ser expresiones enteras.Consulte documentación oficial de DEVOLUCIÓN: https://msdn.microsoft.com/en-us/library/ms174998.aspx.
  2. Su sqlcomm nunca se ejecutó. Debe llamar al sqlcomm.ExecuteNonQuery(); para ejecutar su comando.

Aquí es una solución utilizando parámetros de salida. Esto fue probado con:

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

Puede ser que esto ayudará.

guión

Base de datos:

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 

Aplicación fichero de configuración:

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

capa de acceso a datos (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(); 


     } 


    } 
} 

lógica de negocios de capa (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; 

     } 

    } 
} 

Implementación:

BLL.BLL.InsertUser("@lastid",new SqlParameter("neuname","Ded"), 
       new SqlParameter("neupassword","Moro$ilka"), 
       new SqlParameter("neuposition","Moroz") 
       ); 
1

Cuando volvemos un valor de Procedimiento almacenado sin instrucción de selección. Necesitamos usar el comando "ParameterDirection.ReturnValue" y "ExecuteScalar" para obtener el valor.

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 

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

obtenemos el valor devuelto de SP "IsEmailExists" utilizando lo que antecede función C#.

Cuestiones relacionadas