none
Recuperar @variable = output variable de salida desde store procedure. RRS feed

  • Pregunta

  • Saludos estimados.

    Tengo el siguiente procedimiento almacenado: (El cuál inserta datos en la BD).

    CREATE PROCEDURE [dbo].[pk_GuiaIngresoBodega_Crear]
    	@IdGuiaIngresoBodega	int output, --> Necesito recuperar éste valor devuelto.
    	@IdProveedor			int,	
    	@Fecha					datetime,
    	@OrdenCompra			varchar(50),
    	@Folio					Int,
    	@Total					Decimal(18,0),
    	@Disponible				char(1),
    	@CreadoPor				varchar(25),
    	@FechaIngreso			datetime,
    	@IdTipoDocumento		int
    
    
    AS
    SET NOCOUNT ON
    BEGIN TRANSACTION
    
    	INSERT
    		dbo.cp_GuiaIngresoBodega
    		(
    		cp_GuiaIngresoBodega.IdProveedor,
    		cp_GuiaIngresoBodega.Fecha,
    		cp_GuiaIngresoBodega.OrdenCompra,
    		cp_GuiaIngresoBodega.Folio,
    		cp_GuiaIngresoBodega.Total,		
    		cp_GuiaIngresoBodega.Disponible,
    		cp_GuiaIngresoBodega.CreadoPor,
    		cp_GuiaIngresoBodega.FechaIngreso,
    		cp_GuiaIngresoBodega.IdTipoDocumento
    		)
    	VALUES
    		(
    		@IdProveedor,
    		@Fecha,
    		@OrdenCompra,
    		@Folio,
    		@Total,		
    		@Disponible,
    		@CreadoPor,
    		@FechaIngreso,
    		@IdTipoDocumento
    	)
    
    	IF @@ERROR != 0
    	BEGIN
    		ROLLBACK TRANSACTION
    		RAISERROR ('R -2; Se a generado un error cuando se ejecutaba una transacción en la Base de Datos: SIP. El procedimiento que genero el error se llama : dbo.pk_Proveedor_Crear; Registro ID : %d',10, 2, @IdGuiaIngresoBodega ) WITH LOG
    		RETURN -2
    	END
    
    	SET @IdGuiaIngresoBodega = @@IDENTITY
    
    COMMIT TRANSACTION
    RETURN 0
    

    Como pueden observar en mi procedimiento almacenado, tengo definido éste el @IdGuiaIngresoBodega que lo devuelvo (output) pero necesito recuperarlo en c#.

    Acá está mi método que utiliza éste procedimiento almacenado.

    public int crear_GuiaDetalleDatos(int IdGuiaIngresoBodega, int IdEnvase, decimal cantidad, string comentario, char disponible, string CreadoPor, int unidadmedida, char estado)
            {
                //[Variable procedimiento almacenado.]
                string storeprocedure = "pk_GuiaIngresoBodegaDetalle_Crear";
    
                //[Nueva conexion]
                using (SqlConnection conn = new SqlConnection(ConexionBD.getDataSource()))
                {
                    //[Abriendo conexion BD]
                    conn.Open();
    
                    //[Definiendo comando Sql]
                    SqlCommand cmd          = new SqlCommand(storeprocedure, conn);
                    cmd.CommandType         = CommandType.StoredProcedure;
    
                    //[Parámetro de salida del Procedimiento Almacenado]
                    SqlParameter id_detalle = new SqlParameter("@IdGuiaIngresoBodegaDetalle", SqlDbType.Int);
                    id_detalle.Direction    = ParameterDirection.Output;
    
                    //[Parámetros del Store Procedure]
                    cmd.Parameters.Add(id_detalle);
                    cmd.Parameters.Add("@IdGuiaIngresoBodega", SqlDbType.Int).Value                 = IdGuiaIngresoBodega;
                    cmd.Parameters.Add("@IdEnvase", SqlDbType.Int).Value                            = IdEnvase;
                    cmd.Parameters.Add("@Cantidad", SqlDbType.Decimal, 9).Value                     = cantidad;
                    cmd.Parameters.Add("@Comentario", SqlDbType.VarChar, 100).Value                 = comentario;
                    cmd.Parameters.Add("@Disponible", SqlDbType.Char, 1).Value                      = disponible;
                    cmd.Parameters.Add("@CreadoPor", SqlDbType.VarChar, 25).Value                   = CreadoPor;
                    cmd.Parameters.Add("@IdUnidadMedida", SqlDbType.Int).Value                      = unidadmedida;
                    cmd.Parameters.Add("@Estado", SqlDbType.Char, 1).Value                          = estado;
    
                    int rowsAffected = cmd.ExecuteNonQuery();
    
                    if (rowsAffected > 0)
                    {
                        return Convert.ToInt32(cmd.Parameters["Id"].Value);
                    }
    
                    return 0;
                }
            }

    Tal como expliqué, necesito recuperar el IdGuiaIngresoBodega y guardarlo en una variable o en un Hiddenfield, etc... pero necesito recuperarlo.  ¿Alguien sabe como? desde ya gracias! agradecido de quiénes siempre se dan un tiempo para responder mis inquietudes, he aprendido mucho acá.

    Atte.


    lunes, 20 de febrero de 2012 19:09

Todas las respuestas

  • ¿Alguien que pueda ayudarme?  Es un parámetro de salida OUTPUT, no de retorn RETURNVALUE por siacaso...
    lunes, 20 de febrero de 2012 19:57
  • Lo que tiene debería funcionar con la salvedad de dos detalles:

    1. Usted no tiene que hacer cmd.Parameters["Id"].Value para obtener el valor.  Usted tiene una variable llamada id_detalle que apunta al parámetro de salida, así que puede hacer id_detalle.Value.
    2. El uso de Set NoCount On hace que no se devuelva el total de filas afectadas por el SP y por lo tanto rowsAffected siempre será cero.

    Y con esto no quiero decir que deba quitar el Set NoCount On.  Para nada.  Más bien usted debe variar los parámetros de decisión.  Actualmente usted decide que la ejecución del SP fue exitosa si hubo rowsAffected.  Mal hecho.  Usted debe decidir si la ejecución fue exitosa basándose el el return value del SP.  El SP a como lo muestra aquí está correctamente escrito:  En caso de error devuelve un valor distinto de cero, y en caso de éxito devuelve cero.  Perfecto.

    Lo único que debe cambiar entonces en el C#.  Agregue un parámetro más cuya dirección es ReturnValue (de tipo Int).  Luego ejecute ExecuteNonQuery().  Ahora sí:  Pregunte por el valor del parámetro que era ReturnValue.  Si es cero, entonces confíe en el valor devuelto por el parámetro de salida Id; si no es cero, entonces algo malo pasó y no debe confiar en el valor devuelto en el parámetro de salida Id.


    Jose R. MCP

    lunes, 20 de febrero de 2012 20:15
  • Lo que tiene debería funcionar con la salvedad de dos detalles:

    1. Usted no tiene que hacer cmd.Parameters["Id"].Value para obtener el valor.  Usted tiene una variable llamada id_detalle que apunta al parámetro de salida, así que puede hacer id_detalle.Value.
    2. El uso de Set NoCount On hace que no se devuelva el total de filas afectadas por el SP y por lo tanto rowsAffected siempre será cero.

    Y con esto no quiero decir que deba quitar el Set NoCount On.  Para nada.  Más bien usted debe variar los parámetros de decisión.  Actualmente usted decide que la ejecución del SP fue exitosa si hubo rowsAffected.  Mal hecho.  Usted debe decidir si la ejecución fue exitosa basándose el el return value del SP.  El SP a como lo muestra aquí está correctamente escrito:  En caso de error devuelve un valor distinto de cero, y en caso de éxito devuelve cero.  Perfecto.

    Lo único que debe cambiar entonces en el C#.  Agregue un parámetro más cuya dirección es ReturnValue (de tipo Int).  Luego ejecute ExecuteNonQuery().  Ahora sí:  Pregunte por el valor del parámetro que era ReturnValue.  Si es cero, entonces confíe en el valor devuelto por el parámetro de salida Id; si no es cero, entonces algo malo pasó y no debe confiar en el valor devuelto en el parámetro de salida Id.


    Jose R. MCP


    Gracias, en realidad soy algo novato en c# pero entendí lo que planteas, ¿existe la posibilidad de que me ilustres según el código antes expuesto? De encontrar la solución lo postearé de inmedaito, gracias de antemano.
    lunes, 20 de febrero de 2012 20:49
  • Parameter retVal = cmd.Parameters.Add("retval");
    retVal.Direction = ParameterDirection.ReturnValue;
    
    try
    {
        cmd.ExecuteNonQuery();
    }
    catch(System.Exception ex)
    {
        //Algo malo pasó.  Revisar y tomar la acción apropiada.
    }
    if (Convert.ToInt32(retVal.Value) == 0)
    {
        //Éxitos.
        return Convert.ToInt32(id_detalle.Value);
    }


    Jose R. MCP

    martes, 21 de febrero de 2012 0:07
  • hola

    porque usas

    cmd.Parameters["Id"].Value

    en lugar de

    cmd.Parameters["@IdGuiaIngresoBodegaDetalle"].Value

    digo no se llama asi el parametro que defines como output

    saludos


    Leandro Tuttini

    Blog
    Buenos Aires
    Argentina


    martes, 21 de febrero de 2012 5:27
  • Gracias a ambos por sus sugerencias, lo que quiero al fin y al cabo es que, el valor que retorne el procedimiento almacenado, que sería el @IdIngresoBodega (output), luego recuperarlo -por ejemplo- en un hiddenfield y utilizarlo para lo que requiero.  Voy a poner en práctica vuestros consejos!
    martes, 21 de febrero de 2012 11:50
  • hola

    porque usas

    cmd.Parameters["Id"].Value

    en lugar de

    cmd.Parameters["@IdGuiaIngresoBodegaDetalle"].Value

    digo no se llama asi el parametro que defines como output

    saludos


    Leandro Tuttini

    Blog
    Buenos Aires
    Argentina


    hice ésto y pude recuperar el valor que me retorna el parámetro de salida, ante un ingreso exitoso retorna 0, ante uno fallido uno distinto a 0, por ende con eso yta puedo manejarlo.  Mi método quedó de ésta forma, les agradecería si encuentran alguna detalle para corregirlo.

     //[Insertar nuevo Encabezado con Retorno]:   [PROCEDIMIENTO ALMACENADO: pk_GuiaIngresoBodega_Crear] 
            public int crear_GuiaEncabezadoDatosRetorno(int id_prov, DateTime f_doc, int folio, decimal total, string disp, DateTime f_llegada, int tipo_dcto, string creado_por, string oc)
            {
                //[Variable Store Procedure]
                string storeprocedure = "pk_GuiaIngresoBodega_Crear";
    
                //[Instanciando conexion con BD.]
                using (SqlConnection conn = new SqlConnection(ConexionBD.getDataSource()))
                {
                    //[Abriendo conexion con BD]
                    conn.Open();
    
                    //[Instaciando nuevo comando Sql]
                    SqlCommand cmd                      = new SqlCommand(storeprocedure, conn);
                    cmd.CommandType                     = CommandType.StoredProcedure;
    
                    //[Instanciando parámetro de Salida.]
                    SqlParameter IdGuiaIngresoBodega    = new SqlParameter("@IdGuiaIngresoBodega", SqlDbType.Int);
                    IdGuiaIngresoBodega.Direction       = ParameterDirection.Output;
    
                    //[Instanciando parámetro de Retorno]
                    SqlParameter retVal                 = new SqlParameter("@retval", SqlDbType.Int);
                    retVal.Direction                    = ParameterDirection.ReturnValue;
    
                    //[Instanciando parámetro de Retorno.]
                    SqlParameter id_return              = new SqlParameter("@RETURN", SqlDbType.Int);
                    id_return.Direction                 = ParameterDirection.ReturnValue;
    
                    //[Instaciando parámetros procedimiento almacenado.]
                    cmd.Parameters.Add(retVal);
                    cmd.Parameters.Add(IdGuiaIngresoBodega);
                    cmd.Parameters.Add("@IdProveedor", SqlDbType.Int).Value                             = id_prov;
                    cmd.Parameters.Add("@Fecha", SqlDbType.DateTime).Value                              = f_doc;
                    cmd.Parameters.Add("@OrdenCompra", SqlDbType.VarChar, 50).Value                     = oc;
                    cmd.Parameters.Add("@Folio", SqlDbType.Int).Value                                   = folio;
                    cmd.Parameters.Add("@Total", SqlDbType.Decimal, 18).Value                           = total;
                    cmd.Parameters.Add("@Disponible", SqlDbType.Char, 1).Value                          = Convert.ToChar(disp.Trim());
                    cmd.Parameters.Add("@CreadoPor", SqlDbType.VarChar, 25).Value                       = creado_por;
                    cmd.Parameters.Add("@FechaIngreso", SqlDbType.DateTime).Value                       = f_llegada;
                    cmd.Parameters.Add("@IdTipoDocumento", SqlDbType.Int).Value                         = tipo_dcto;
    
                    int rowsAffected = cmd.ExecuteNonQuery();
    
                    if (rowsAffected > 0)
                    {
                        return Convert.ToInt32(cmd.Parameters["@IdGuiaIngresoBodegaDetalle"].Value);
                    }
                    else
                    {
                        return 0;
                    }
                }
            }

    Y éste es mi store procedure.

    ALTER PROCEDURE [dbo].[pk_GuiaIngresoBodega_Crear]
    	@IdGuiaIngresoBodega	int output,
    	@IdProveedor			int,	
    	@Fecha					datetime,
    	@OrdenCompra			varchar(50),
    	@Folio					Int,
    	@Total					Decimal(18,0),
    	@Disponible				char(1),
    	@CreadoPor				varchar(25),
    	@FechaIngreso			datetime,
    	@IdTipoDocumento		int
    
    
    AS
    SET NOCOUNT ON
    BEGIN TRANSACTION
    
    	INSERT
    		dbo.cp_GuiaIngresoBodega
    		(
    		cp_GuiaIngresoBodega.IdProveedor,
    		cp_GuiaIngresoBodega.Fecha,
    		cp_GuiaIngresoBodega.OrdenCompra,
    		cp_GuiaIngresoBodega.Folio,
    		cp_GuiaIngresoBodega.Total,		
    		cp_GuiaIngresoBodega.Disponible,
    		cp_GuiaIngresoBodega.CreadoPor,
    		cp_GuiaIngresoBodega.FechaIngreso,
    		cp_GuiaIngresoBodega.IdTipoDocumento
    		)
    	VALUES
    		(
    		@IdProveedor,
    		@Fecha,
    		@OrdenCompra,
    		@Folio,
    		@Total,		
    		@Disponible,
    		@CreadoPor,
    		@FechaIngreso,
    		@IdTipoDocumento
    	)
    
    	IF @@ERROR != 0
    	BEGIN
    		ROLLBACK TRANSACTION
    		RAISERROR ('R -2; Se a generado un error cuando se ejecutaba una transacción en la Base de Datos: SIP. El procedimiento que genero el error se llama : dbo.pk_Proveedor_Crear; Registro ID : %d',10, 2, @IdGuiaIngresoBodega ) WITH LOG
    		RETURN -2
    	END
    
    	SET @IdGuiaIngresoBodega = @@IDENTITY
    
    COMMIT TRANSACTION
    RETURN 0

    martes, 21 de febrero de 2012 12:30
  • Pero me comí un groso detalle...  ccon el código que tengo actualmente recupero si es 0 o distinto a =, es decir, si el INSERT se realizó corréctamente o no.  Pero necesito recuperar el valor del @IdIngresoBodega que corresponde a la columna ID de la tabla IngresoBodega, ya que con ese ID tengo que trabajar posteriomente.

    Por ejemplo, si inserto corréctamente, el ID autogenerado en la tabla IngresoBodega sería =145, ese ID tengo que recuperarlo para utilizarlo posteriormente :(

    martes, 21 de febrero de 2012 13:31
  • hola

    [ADO.NET] – Parte 6 - Ejemplos simples – Campos identity

    revisa el titulo "3 – Obtener Id desde Stored Procedure"

    saludos


    Leandro Tuttini

    Blog
    Buenos Aires
    Argentina


    martes, 21 de febrero de 2012 14:00
  • pero sigues cometiendo el mismo fallo que antes

    si defines

    SqlParameter IdGuiaIngresoBodega    = new SqlParameter("@IdGuiaIngresoBodega", SqlDbType.Int);

    como vas a usar

    return Convert.ToInt32(cmd.Parameters["@IdGuiaIngresoBodegaDetalle"].Value);

    como es que usas IdGuiaIngresoBodegaDetalle sino lo defienes, estas declarando IdGuiaIngresoBodega, ese debes usar para tomar el valor devuelto

    saludos


    Leandro Tuttini

    Blog
    Buenos Aires
    Argentina

    martes, 21 de febrero de 2012 14:02
  • pero sigues cometiendo el mismo fallo que antes

    si defines

    SqlParameter IdGuiaIngresoBodega    = new SqlParameter("@IdGuiaIngresoBodega", SqlDbType.Int);

    como vas a usar

    return Convert.ToInt32(cmd.Parameters["@IdGuiaIngresoBodegaDetalle"].Value);

    como es que usas IdGuiaIngresoBodegaDetalle sino lo defienes, estas declarando IdGuiaIngresoBodega, ese debes usar para tomar el valor devuelto

    saludos


    Leandro Tuttini

    Blog
    Buenos Aires
    Argentina

    Voy a estudiar el link que me pasaste.  Dicho sea de paso, finalmente logré recuperar el ID de ésta forma, quizás tengo errores pero lo estudiaré y corregiré gracias a vuestra ayuda.

     public int crear_GuiaEncabezadoDatos(int id_prov, DateTime f_doc, int folio, decimal total, string disp, DateTime f_llegada, int tipo_dcto, string creado_por, string oc)
            {
                //[Variable Store Procedure]
                string storeprocedure = "pk_GuiaIngresoBodega_Crear";
    
                //[Instanciando conexion con BD.]
                using (SqlConnection conn = new SqlConnection(ConexionBD.getDataSource()))
                {
                    //[Abriendo conexion con BD]
                    conn.Open();
    
                    //[Instaciando nuevo comando Sql]
                    SqlCommand cmd                      = new SqlCommand(storeprocedure, conn);
                    cmd.CommandType                     = CommandType.StoredProcedure;
    
                    //[Instanciando parámetro de Salida.]
                    SqlParameter IdGuiaIngresoBodega    = new SqlParameter("@IdGuiaIngresoBodega", SqlDbType.Int);
                    IdGuiaIngresoBodega.Direction       = ParameterDirection.Output;
    
                    //[Instanciando parámetro de Retorno]
                    SqlParameter retVal                 = new SqlParameter("@retval", SqlDbType.Int);
                    retVal.Direction                    = ParameterDirection.ReturnValue;
    
            
    
                    //[Instaciando parámetros procedimiento almacenado.]
                    cmd.Parameters.Add(IdGuiaIngresoBodega);
                    cmd.Parameters.Add(retVal);
                    cmd.Parameters.Add("@IdProveedor", SqlDbType.Int).Value                             = id_prov;
                    cmd.Parameters.Add("@Fecha", SqlDbType.DateTime).Value                              = f_doc;
                    cmd.Parameters.Add("@OrdenCompra", SqlDbType.VarChar, 50).Value                     = oc;
                    cmd.Parameters.Add("@Folio", SqlDbType.Int).Value                                   = folio;
                    cmd.Parameters.Add("@Total", SqlDbType.Decimal, 18).Value                           = total;
                    cmd.Parameters.Add("@Disponible", SqlDbType.Char, 1).Value                          = Convert.ToChar(disp.Trim());
                    cmd.Parameters.Add("@CreadoPor", SqlDbType.VarChar, 25).Value                       = creado_por;
                    cmd.Parameters.Add("@FechaIngreso", SqlDbType.DateTime).Value                       = f_llegada;
                    cmd.Parameters.Add("@IdTipoDocumento", SqlDbType.Int).Value                         = tipo_dcto;
    
                    int rowsAffected = cmd.ExecuteNonQuery();
    
                    if ((Convert.ToInt32(cmd.Parameters["@retval"].Value) == 0))
                    {
                        return Convert.ToInt32(cmd.Parameters["@IdGuiaIngresoBodega"].Value);
                    }
                    else
                    {
                        return 1;
                    }
                }
            }
    

    martes, 21 de febrero de 2012 15:27
  • Eso está bien por la mayor parte.  Lo que no veo es el try...catch porque si el SP hace RAISERROR entonces en .Net se genera una excepción.  Y lo otro sería hacerle ver que puede usar las variables IdGuiaIngresoBodega y retVal para preguntar por sus valores.  O sea, en el if al final, en vez de cmd.Parameters["@retval"].Value, puede usar retVal.Value; igualmente con la otra línea pero con la otra variable.

    Jose R. MCP

    martes, 21 de febrero de 2012 15:45
  • Amigo, has esto:

    ALTER PROCEDURE [dbo].[pk_GuiaIngresoBodega_Crear] @IdGuiaIngresoBodega int output, @IdProveedor int, @Fecha datetime, @OrdenCompra varchar(50), @Folio Int, @Total Decimal(18,0), @Disponible char(1), @CreadoPor varchar(25), @FechaIngreso datetime, @IdTipoDocumento int AS SET NOCOUNT ON BEGIN TRANSACTION INSERT dbo.cp_GuiaIngresoBodega ( cp_GuiaIngresoBodega.IdProveedor, cp_GuiaIngresoBodega.Fecha, cp_GuiaIngresoBodega.OrdenCompra, cp_GuiaIngresoBodega.Folio, cp_GuiaIngresoBodega.Total, cp_GuiaIngresoBodega.Disponible, cp_GuiaIngresoBodega.CreadoPor, cp_GuiaIngresoBodega.FechaIngreso, cp_GuiaIngresoBodega.IdTipoDocumento ) VALUES ( @IdProveedor, @Fecha, @OrdenCompra, @Folio, @Total, @Disponible, @CreadoPor, @FechaIngreso, @IdTipoDocumento ) IF @@ERROR != 0 BEGIN ROLLBACK TRANSACTION RAISERROR ('R -2; Se a generado un error cuando se ejecutaba una transacción en la Base de Datos: SIP. El procedimiento que genero el error se llama : dbo.pk_Proveedor_Crear; Registro ID : %d',10, 2, @IdGuiaIngresoBodega ) WITH LOG RETURN -2 END SET @IdGuiaIngresoBodega = @@IDENTITY

    SELECT @IdGuiaIngresoBodega

    COMMIT TRANSACTION RETURN 0

    Luego desde tu código llamas al SP pero cambias esta linea int rowsAffected = cmd.ExecuteNonQuery(); por esta string guiaIngreso = cmd.ExecuteScalar(); el cual te retornará el registro que se encuentre en la row 0 de la columna 0 es decir, tu @IdGuiaIngresoBodega ya que al SP le hiciste un SELECT @IdGuiaIngresoBodega.

    Espero haberte ayudado, si necesita más ayuda avisame :D


    Raul :D

    martes, 21 de febrero de 2012 16:15
  • Raúl, eso serviría si el SP no devuelve resultados.  ¿Pero qué pasaría si además del dato hay que devolver otros resultados?  Lo mejor es que aprenda a usar los parámetros de salida tal y como lo está haciendo ahora.

    Jose R. MCP

    martes, 21 de febrero de 2012 16:18
  • Mmm pero para éste caso funciona, de igual manera el escenario se plantea de la forma como yo lo resuelvo. Pero bueno, podemos hacer lo siguiente entonces:

    cmd.Parameters.AddWithValue("@IdGuiaIngresoBodega","").Direction = ParameterDirection.Output;

    cmd.ExecuteNonQuery();

    string resultadoParametroSalida = sqlCommand.Parameters["@IdGuiaIngresoBodega"].ToString();

    Y me imagino que debería funcionar :)


    Raul :D

    martes, 21 de febrero de 2012 16:26