2012-06-05 19 views
42

Tengo un problema al devolver un parámetro de salida de un procedimiento almacenado de SQL Server en una variable C#. He leído las otras publicaciones relacionadas con esto, no solo aquí, sino en otros sitios, y no puedo hacer que funcione. Esto es lo que tengo actualmente. Actualmente estoy tratando de imprimir el valor que vuelve. El siguiente código devuelve un valor nulo. Lo que intento devolver es la clave principal. He intentado usar @@IDENTITY y SCOPE_INDENTITY() (es decir, SET @NewId = SCOPE_IDENTITY()).Uso de parámetros de salida de procedimiento almacenado en C#

procedimiento almacenado:

CREATE PROCEDURE usp_InsertContract 
    @ContractNumber varchar(7), 

    @NewId int OUTPUT 
AS 
BEGIN 

    INSERT into [dbo].[Contracts] (ContractNumber) 
     VALUES (@ContractNumber) 

    Select @NewId = Id From [dbo].[Contracts] where ContractNumber = @ContractNumber 
END 

Abrir la base de datos:

pvConnectionString = "Server = Desktop-PC\\SQLEXPRESS; Database = PVDatabase; User ID = sa; 
    PASSWORD = *******; Trusted_Connection = True;"; 

try 
{ 
    pvConnection = new SqlConnection(pvConnectionString); 
    pvConnection.Open(); 
} 
catch (Exception e) 
{ 
    databaseError = true; 
} 

La ejecución del comando:

pvCommand = new SqlCommand("usp_InsertContract", pvConnection); 

pvCommand.Transaction = pvTransaction; 
pvCommand.CommandType = CommandType.StoredProcedure;  

pvCommand.Parameters.Clear(); 
pvCommand.Parameters.Add(new SqlParameter("@ContractNumber", contractNumber)); 

SqlParameter pvNewId = new SqlParameter(); 
pvNewId.ParameterName = "@NewId"; 
pvNewId.DbType = DbType.Int32; 
pvNewId.Direction = ParameterDirection.Output; 
pvCommand.Parameters.Add(pvNewId); 

try 
{ 
    sqlRows = pvCommand.ExecuteNonQuery(); 

    if (sqlRows > 0) 
     Debug.Print("New Id Inserted = ", 
      pvCommand.Parameters["@NewId"].Value.ToString()); 
    } 
    catch (Exception e) 
    { 
     Debug.Print("Insert Exception Type: {0}", e.GetType()); 
     Debug.Print(" Message: {0}", e.Message); 
    } 
} 
+1

También usaría SCOPE_IDENTITY() en lugar de volver a consultar la misma tabla, y en caso de que aparezca el error "la consulta puede devolver varios resultados", al asignar a una sola salida var. – JMC

+0

¿Utilizo el comando set para hacer esto?SET NewId = SCOPE_IDENTITY()? Reemplacé la declaración de selección con lo siguiente ... SET @NewId = SCOPE_IDENTITY() y aún recibo un valor nulo de nuevo. – Gary

+0

Por supuesto, puede confirmar que el nuevo registro está realmente insertado, ¿verdad? ¿Podría mostrar más de su código C# (la apertura de la conexión, la creación de comandos, etc.) – Steve

Respuesta

1

procedimiento almacenado .........

CREATE PROCEDURE usp_InsertContract 
    @ContractNumber varchar(7) 
AS 
BEGIN 

    INSERT into [dbo].[Contracts] (ContractNumber) 
     VALUES (@ContractNumber) 

    SELECT SCOPE_IDENTITY() AS [SCOPE_IDENTITY] 
END 

C#

pvCommand.CommandType = CommandType.StoredProcedure; 

pvCommand.Parameters.Clear(); 
pvCommand.Parameters.Add(new SqlParameter("@ContractNumber", contractNumber)); 
object uniqueId; 
int id; 
    try 
    { 
    uniqueId = pvCommand.ExecuteScalar(); 
    id = Convert.ToInt32(uniqueId); 
    } 
    catch (Exception e) 
    { 
     Debug.Print(" Message: {0}", e.Message); 
    } 
} 

EDIT: "Todavía regrese un valor DBNull .... objeto no se puede lanzar desde DBNull a otros tipos. Tomaré esto de nuevo mañana. Me voy a mi otro trabajo,"

creo que la columna Id en su tabla de SQL no es una columna de identidad.

enter image description here

+0

Pero esto no responde a la pregunta de por qué el parámetro de salida para la nueva identificación devuelve nulo. Con 'ExecuteScalar' puedes recuperar un valor devuelto no un parámetro de salida. –

+0

También recibo el siguiente error cuando realizo este cambio ... Referencia de objeto no establecida en una instancia de un objeto. – Gary

+0

Eso es porque el parámetro se llama SCOPE_IDENTITY, en SQL; C# todavía está buscando un parámetro llamado @ContractNumber. –

82

que modificó ligeramente el procedimiento almacenado (para usar SCOPE_IDENTITY) y se ve así:

CREATE PROCEDURE usp_InsertContract 
    @ContractNumber varchar(7), 
    @NewId int OUTPUT 
AS 
BEGIN 
    INSERT INTO [dbo].[Contracts] (ContractNumber) 
    VALUES (@ContractNumber) 

    SELECT @NewId = SCOPE_IDENTITY() 
END 

he intentado esto y funciona muy bien (con ese procedimiento almacenado modificado):

// define connection and command, in using blocks to ensure disposal 
using(SqlConnection conn = new SqlConnection(pvConnectionString)) 
using(SqlCommand cmd = new SqlCommand("dbo.usp_InsertContract", conn)) 
{ 
    cmd.CommandType = CommandType.StoredProcedure; 

    // set up the parameters 
    cmd.Parameters.Add("@ContractNumber", SqlDbType.VarChar, 7); 
    cmd.Parameters.Add("@NewId", SqlDbType.Int).Direction = ParameterDirection.Output; 

    // set parameter values 
    cmd.Parameters["@ContractNumber"].Value = contractNumber; 

    // open connection and execute stored procedure 
    conn.Open(); 
    cmd.ExecuteNonQuery(); 

    // read output value from @NewId 
    int contractID = Convert.ToInt32(cmd.Parameters["@NewId"].Value); 
    conn.Close(); 
} 

¿Esto funciona en su entorno, también? No puedo decir por qué su código original no funcionará, pero cuando hago esto aquí, VS2010 y SQL Server 2008 R2, simplemente funciona perfectamente ...

Si no obtiene un valor de retorno - entonces sospecho que su tabla Contracts podría no tener realmente una columna con la propiedad IDENTITY.

+3

+1 ¡muchas gracias por hacerse cargo! –

+6

¡Gracias! Le agradezco su tiempo al responder esto a aquellos de nosotros que buscamos en Google años después. :-) –

+0

@marc_s si no se conoce el tamaño de la salida de Varchar, entonces cómo abordar ese problema. – Gunner

3

Antes de cambiar el procedimiento almacenado, compruebe cuál es el resultado de su actual. En SQL Server Management ejecute lo siguiente:

DECLARE @NewId int 
EXEC @return_value = [dbo].[usp_InsertContract] 
      N'Gary', 
      @NewId OUTPUT 
SELECT @NewId 

Vea lo que devuelve. Esto puede darle algunos indicios de por qué su param no está lleno.

+0

Esto funciona como una respuesta, pero probablemente debería ser un comentario, sin embargo, no puedo convertirlo debido al uso de varios caracteres @ (incluso las modificaciones se niegan así) y no me molesta editarlo para hacerlo trabajo. :) – Kev

0

En su código C#, está utilizando la transacción para el comando. Simplemente confirme la transacción y luego acceda a su valor de parámetro, obtendrá el valor. Funcionó para mí. :)

Cuestiones relacionadas