Llamar al procedimiento almacenado con valor de retorno

82

Estoy intentando llamar a un procedimiento almacenado desde mi aplicación de Windows C #. El procedimiento almacenado se está ejecutando en una instancia local de SQL Server 2008. Puedo llamar al procedimiento almacenado pero no puedo recuperar el valor del procedimiento almacenado. Se supone que este procedimiento almacenado devuelve el siguiente número de la secuencia. He investigado en línea y todos los sitios que he visto apuntan a que esta solución funciona.

Código de procedimiento almacenado:

ALTER procedure [dbo].[usp_GetNewSeqVal]
      @SeqName nvarchar(255)
as
begin
      declare @NewSeqVal int
      set NOCOUNT ON
      update AllSequences
      set @NewSeqVal = CurrVal = CurrVal+Incr
      where SeqName = @SeqName

      if @@rowcount = 0 begin
print 'Sequence does not exist'
            return
      end

      return @NewSeqVal
end

Código que llama al procedimiento almacenado:

SqlConnection conn = new SqlConnection(getConnectionString());
conn.Open();

SqlCommand cmd = new SqlCommand(parameterStatement.getQuery(), conn);
cmd.CommandType = CommandType.StoredProcedure;

SqlParameter param = new SqlParameter();

param = cmd.Parameters.Add("@SeqName", SqlDbType.NVarChar);
param.Direction = ParameterDirection.Input;
param.Value = "SeqName";

SqlDataReader reader = cmd.ExecuteReader();

También intenté usar a DataSetpara recuperar el valor de retorno con el mismo resultado. ¿Qué me falta para obtener el valor de retorno de mi procedimiento almacenado? Si necesita más información, hágamelo saber.

Wesley
fuente

Respuestas:

165

Debe agregar el parámetro de retorno al comando:

using (SqlConnection conn = new SqlConnection(getConnectionString()))
using (SqlCommand cmd = conn.CreateCommand())
{
    cmd.CommandText = parameterStatement.getQuery();
    cmd.CommandType = CommandType.StoredProcedure;
    cmd.Parameters.AddWithValue("SeqName", "SeqNameValue");

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

    conn.Open();
    cmd.ExecuteNonQuery();
    var result = returnParameter.Value;
}
Alex Aza
fuente
3
¿Tiene que agregar también @ReturnValal procedimiento almacenado?
muttley91
4
No, no tiene que agregar al sp (la declaración de retorno activa el llenado del parámetro marcado con ReturnValue)
ufosnowcat
10
No importa cómo nombre el parámetro return val, por cierto.
Clay
muchas gracias, estaba buscando una manera de obtener correctamente el valor de retorno, esto realmente funcionó para mí. ¡increíble!
Oswaldo Zapata
4
El valor de retorno del procedimiento almacenado debe usarse solo para indicar éxito (cero) o falla / advertencia (distinto de cero), no para devolver datos. Utilice un OUTPUTparámetro o conjunto de resultados para ese propósito.
Dan Guzman
5

Sé que esto es antiguo, pero lo encontré con Google.

Si tiene un valor de retorno en su procedimiento almacenado, diga "Retorno 1", sin usar parámetros de salida.

Puede hacer lo siguiente: "@RETURN_VALUE" se agrega silenciosamente a cada objeto de comando. NO ES NECESARIO AGREGAR EXPLÍCITAMENTE

    cmd.ExecuteNonQuery();
    rtn = (int)cmd.Parameters["@RETURN_VALUE"].Value;
Gary
fuente
2
Hola Gary. ¿Tiene una citación?
Michael
5
No creo que la instancia de cmd tenga un parámetro nombrado en RETURN_VALUE en SqlParameterCollection a menos que se agregue explícitamente. Por lo tanto, si está considerando tomar el enfoque anterior de Gary, asegúrese de haber agregado cmd.Parameters.Add (new SqlParameter ("@ RETURN_VALUE", SqlDbType.Int)); cmd.Parameters ["@ RETURN_VALUE"]. Dirección = ParameterDirection.ReturnValue; Sin embargo, creo que NO tiene que agregar @RETURN_VALUE a la definición del procedimiento almacenado. Quizás eso es lo que Gary quiso decir.
jbooker
4

La versión de EnterpriseLibrary en mi máquina tenía otros parámetros. Esto estaba funcionando:

        SqlParameter retval = new SqlParameter("@ReturnValue", System.Data.SqlDbType.Int);
        retval.Direction = System.Data.ParameterDirection.ReturnValue;
        cmd.Parameters.Add(retval);
        db.ExecuteNonQuery(cmd);
        object o = cmd.Parameters["@ReturnValue"].Value;
RaSor
fuente
3

ExecuteScalar(); funcionará, pero un parámetro de salida sería una solución superior.

Justin Dearing
fuente
7
ExecuteScalar () no funciona, a menos que "seleccione" el valor de retorno.
Soori
2

Tuve un problema similar con la llamada SP que devolvió un error de que no se incluyó un parámetro esperado. Mi código fue el siguiente.
Procedimiento almacenado:

@Resultado int SALIDA

Y C#:

            SqlParameter result = cmd.Parameters.Add(new SqlParameter("@Result", DbType.Int32));
            result.Direction = ParameterDirection.ReturnValue;

En la resolución de problemas, me di cuenta de que el procedimiento almacenado estaba REALMENTE buscando una dirección de "InputOutput", por lo que el siguiente cambio solucionó el problema.

            r

Result.Direction = ParameterDirection.InputOutput;

Pablo
fuente
1
Los "parámetros de salida" no son lo mismo que los valores de retorno del procedimiento almacenado, por cierto.
Dai
0

O si está utilizando EnterpriseLibrary en lugar de ADO.NET estándar ...

Database db = DatabaseFactory.CreateDatabase();
using (DbCommand cmd = db.GetStoredProcCommand("usp_GetNewSeqVal"))
{
    db.AddInParameter(cmd, "SeqName", DbType.String, "SeqNameValue");
    db.AddParameter(cmd, "RetVal", DbType.Int32, ParameterDirection.ReturnValue, null, DataRowVersion.Default, null);

    db.ExecuteNonQuery(cmd);

    var result = (int)cmd.Parameters["RetVal"].Value;
}
Dunc
fuente
0

Esta es una muestra muy breve de devolver un solo valor de un procedimiento:

SQL:

CREATE PROCEDURE [dbo].[MakeDouble] @InpVal int AS BEGIN 
SELECT @InpVal * 2; RETURN 0; 
END

Código C #:

int inpVal = 11;
string retVal = "?";
using (var sqlCon = new SqlConnection(
    "Data Source = . ; Initial Catalog = SampleDb; Integrated Security = True;"))
{
    sqlCon.Open();
    retVal = new SqlCommand("Exec dbo.MakeDouble " + inpVal + ";", 
        sqlCon).ExecuteScalar().ToString();
    sqlCon.Close();
}
Debug.Print(inpVal + " * 2 = " + retVal); 
//> 11 * 2 = 22
Michael Borg
fuente
-8

Veo que el otro está cerrado. Básicamente, aquí está el borrador de mi código. Creo que te falta el comentario de la cadena cmd. Por ejemplo, si mi procedimiento de tienda es llamar: DBO.Test. Necesitaría escribir cmd = "DBO.test". Luego haga el tipo de comando igual al procedimiento de almacenamiento, y bla, bla, bla

Connection.open();
String cmd="DBO.test"; //the command
Sqlcommand mycommand;
Lluvia
fuente