Obtener el valor del parámetro de salida en ADO.NET

96

Mi procedimiento almacenado tiene un parámetro de salida:

@ID INT OUT

¿Cómo puedo recuperar esto usando ado.net?

using (SqlConnection conn = new SqlConnection(...))
{
    SqlCommand cmd = new SqlCommand("sproc", conn);
    cmd.CommandType = CommandType.StoredProcedure;

    // add parameters

    conn.Open();

    // *** read output parameter here, how?
    conn.Close();
}
abatishchev
fuente

Respuestas:

119

La otra muestra de respuesta a esto, pero básicamente sólo tiene que crear una SqlParameter, establecen el Directiona Output, y agregarlo a la SqlCommand's Parameterscolección. Luego ejecute el procedimiento almacenado y obtenga el valor del parámetro.

Usando su ejemplo de código:

// SqlConnection and SqlCommand are IDisposable, so stack a couple using()'s
using (SqlConnection conn = new SqlConnection(connectionString))
using (SqlCommand cmd = new SqlCommand("sproc", conn))
{
   // Create parameter with Direction as Output (and correct name and type)
   SqlParameter outputIdParam = new SqlParameter("@ID", SqlDbType.Int)
   { 
      Direction = ParameterDirection.Output 
   };

   cmd.CommandType = CommandType.StoredProcedure;
   cmd.Parameters.Add(outputIdParam);

   conn.Open();
   cmd.ExecuteNonQuery();

   // Some various ways to grab the output depending on how you would like to
   // handle a null value returned from the query (shown in comment for each).

   // Note: You can use either the SqlParameter variable declared
   // above or access it through the Parameters collection by name:
   //   outputIdParam.Value == cmd.Parameters["@ID"].Value

   // Throws FormatException
   int idFromString = int.Parse(outputIdParam.Value.ToString());

   // Throws InvalidCastException
   int idFromCast = (int)outputIdParam.Value; 

   // idAsNullableInt remains null
   int? idAsNullableInt = outputIdParam.Value as int?; 

   // idOrDefaultValue is 0 (or any other value specified to the ?? operator)
   int idOrDefaultValue = outputIdParam.Value as int? ?? default(int); 

   conn.Close();
}

Tenga cuidado al obtener el Parameters[].Value, ya que el tipo debe convertirse desde el objectque lo está declarando. Y se SqlDbTypeusa cuando crea las SqlParameternecesidades para que coincidan con el tipo en la base de datos. Si solo va a Parameters["@Param"].Value.ToString()enviarlo a la consola, es posible que solo esté usando (ya sea explícita o implícitamente a través de una llamada Console.Write()o String.Format()).

EDITAR: Más de 3.5 años y casi 20k visitas y nadie se había molestado en mencionar que ni siquiera se compiló por la razón especificada en mi comentario de "ten cuidado" en la publicación original. Agradable. Se corrigió en base a los buenos comentarios de @Walter Stabosz y @Stephen Kennedy y para que coincida con la edición del código de actualización en la pregunta de @abatishchev.

BQ.
fuente
8
No es necesario, conn.Close()ya que está dentro de un usingbloque
Marcus
1
Creo que su uso de int.MaxValue como la propiedad Size es incorrecto. int.MaxValue es una constante con el valor 2,147,483,647. msdn.microsoft.com/en-us/library/… . El error es inofensivo en este ejemplo porque el tipo de datos es Int y "Para tipos de datos de longitud fija, se ignora el valor de Size", pero un cero habría sido suficiente.
Walter Stabosz
.Value es de tipo objeto, por lo que asignarlo directamente a un int sin conversión no va a funcionar.
Stephen Kennedy
1
Para aquellos que utilizan un DataReader, deben cerrarlo o leer hasta el final de los datos antes de poder ver los parámetros de salida.
Garry English
56

Para cualquiera que busque hacer algo similar usando un lector con el procedimiento almacenado, tenga en cuenta que el lector debe estar cerrado para recuperar el valor de salida.

using (SqlConnection conn = new SqlConnection())
{
    SqlCommand cmd = new SqlCommand("sproc", conn);
    cmd.CommandType = CommandType.StoredProcedure;

    // add parameters
    SqlParameter outputParam = cmd.Parameters.Add("@ID", SqlDbType.Int);
    outputParam.Direction = ParameterDirection.Output;

    conn.Open();

    using(IDataReader reader = cmd.ExecuteReader())
    {
        while(reader.Read())
        {
            //read in data
        }
    }
    // reader is closed/disposed after exiting the using statement
    int id = outputParam.Value;
}
Nate Kindrew
fuente
4
Me perdí el hecho de que el lector debe estar cerrado antes de leer el parámetro de salida. ¡Gracias por señalar eso!
Nicklas Møller Jepsen
28

No es mi código, pero creo que es un buen ejemplo

fuente: http://www.eggheadcafe.com/PrintSearchContent.asp?LINKID=624

using System; 
using System.Data; 
using System.Data.SqlClient; 


class OutputParams 
{ 
    [STAThread] 
    static void Main(string[] args) 
    { 

    using( SqlConnection cn = new SqlConnection("server=(local);Database=Northwind;user id=sa;password=;")) 
    { 
        SqlCommand cmd = new SqlCommand("CustOrderOne", cn); 
        cmd.CommandType=CommandType.StoredProcedure ; 

        SqlParameter parm= new SqlParameter("@CustomerID",SqlDbType.NChar) ; 
        parm.Value="ALFKI"; 
        parm.Direction =ParameterDirection.Input ; 
        cmd.Parameters.Add(parm); 

        SqlParameter parm2= new SqlParameter("@ProductName",SqlDbType.VarChar); 
        parm2.Size=50; 
        parm2.Direction=ParameterDirection.Output; 
        cmd.Parameters.Add(parm2); 

        SqlParameter parm3=new SqlParameter("@Quantity",SqlDbType.Int); 
        parm3.Direction=ParameterDirection.Output; 
        cmd.Parameters.Add(parm3);

        cn.Open(); 
        cmd.ExecuteNonQuery(); 
        cn.Close(); 

        Console.WriteLine(cmd.Parameters["@ProductName"].Value); 
        Console.WriteLine(cmd.Parameters["@Quantity"].Value.ToString());
        Console.ReadLine(); 
    } 
} 
WACM161
fuente
2
Sí, esto es correcto. Simplemente configure la propiedad ParameterDirection del parámetro. No necesita la línea cn.Close (); el bloque using {} se encarga de eso.
MusiGenesis
6
string ConnectionString = ConfigurationManager.ConnectionStrings["DBCS"].ConnectionString;
using (SqlConnection con = new SqlConnection(ConnectionString))
{
//Create the SqlCommand object
SqlCommand cmd = new SqlCommand(“spAddEmployee”, con);

//Specify that the SqlCommand is a stored procedure
cmd.CommandType = System.Data.CommandType.StoredProcedure;

//Add the input parameters to the command object
cmd.Parameters.AddWithValue(“@Name”, txtEmployeeName.Text);
cmd.Parameters.AddWithValue(“@Gender”, ddlGender.SelectedValue);
cmd.Parameters.AddWithValue(“@Salary”, txtSalary.Text);

//Add the output parameter to the command object
SqlParameter outPutParameter = new SqlParameter();
outPutParameter.ParameterName = @EmployeeId”;
outPutParameter.SqlDbType = System.Data.SqlDbType.Int;
outPutParameter.Direction = System.Data.ParameterDirection.Output;
cmd.Parameters.Add(outPutParameter);

//Open the connection and execute the query
con.Open();
cmd.ExecuteNonQuery();

//Retrieve the value of the output parameter
string EmployeeId = outPutParameter.Value.ToString();
}

Fuente http://www.codeproject.com/Articles/748619/ADO-NET-How-to-call-a-stored-procedure-with-output

Vinícius Todesco
fuente
6
public static class SqlParameterExtensions
{
    public static T GetValueOrDefault<T>(this SqlParameter sqlParameter)
    {
        if (sqlParameter.Value == DBNull.Value 
            || sqlParameter.Value == null)
        {
            if (typeof(T).IsValueType)
                return (T)Activator.CreateInstance(typeof(T));

            return (default(T));
        }

        return (T)sqlParameter.Value;
    }
}


// Usage
using (SqlConnection conn = new SqlConnection(connectionString))
using (SqlCommand cmd = new SqlCommand("storedProcedure", conn))
{
   SqlParameter outputIdParam = new SqlParameter("@ID", SqlDbType.Int)
   { 
      Direction = ParameterDirection.Output 
   };

   cmd.CommandType = CommandType.StoredProcedure;
   cmd.Parameters.Add(outputIdParam);

   conn.Open();
   cmd.ExecuteNonQuery();

   int result = outputIdParam.GetValueOrDefault<int>();
}
Greg R. Taylor
fuente
3

Puede obtener su resultado mediante el siguiente código:

using (SqlConnection conn = new SqlConnection(...))
{
    SqlCommand cmd = new SqlCommand("sproc", conn);
    cmd.CommandType = CommandType.StoredProcedure;

    // add other parameters parameters

    //Add the output parameter to the command object
    SqlParameter outPutParameter = new SqlParameter();
    outPutParameter.ParameterName = "@Id";
    outPutParameter.SqlDbType = System.Data.SqlDbType.Int;
    outPutParameter.Direction = System.Data.ParameterDirection.Output;
    cmd.Parameters.Add(outPutParameter);

    conn.Open();
    cmd.ExecuteNonQuery();

    //Retrieve the value of the output parameter
    string Id = outPutParameter.Value.ToString();

    // *** read output parameter here, how?
    conn.Close();
}

fuente
2

Cree el SqlParamObject que le daría control para acceder a los métodos en los parámetros

:

SqlParameter param = new SqlParameter ();

ESTABLEZCA el nombre de su parámetro (debería ser el mismo que habría declarado una variable para mantener el valor en su base de datos)

: param.ParameterName = "@yourParamterName";

Limpiar el contenedor de valor para guardar sus datos de salida

: param.Value = 0;

Establezca la dirección de su elección (en su caso, debería ser Salida)

: param.Direction = System.Data.ParameterDirection.Output;

Sandeep Pandey
fuente
1

Eso me parece más explícito:

¿En t? id = outputIdParam.Value es DbNull? predeterminado (int?): outputIdParam.Value;

Genn
fuente