2010-07-22 17 views
16

Sé que hay otra pregunta con casi el mismo título, pero no responde mi pregunta. Tengo un procedimiento almacenado, que devuelve el identificador único después de la inserción (@@ identidad). Lo probé en el explorador del servidor y funciona como se esperaba (@RETURN_VALUE = [identificador]). En mi código, agregué un parámetro llamado "@RETURN_VALUE", con la dirección ReturnValue primero, que cualquier otro parámetro, pero cuando ejecuto mi consulta con ExecuteNonQuery() ese parámetro permanece vacío. No sé lo que hice mal. Mi sproc:Obtener el valor de retorno del procedimiento almacenado en ADO.NET

ALTER PROCEDURE dbo.SetAuction 
(
    @auctionID int, 
    @itemID int, 
    @auctionType tinyint, 
    @reservationPrice int, 
    @maxPrice int, 
    @auctionEnd datetime, 
    @auctionStart datetime, 
    @auctionTTL tinyint, 
    @itemName nchar(50), 
    @itemDescription nvarchar(MAX), 
    @categoryID tinyint, 
    @categoryName nchar(50) 
) AS 
IF @auctionID <> 0 
    BEGIN 
    BEGIN TRAN T1 

    UPDATE Auction 
    SET AuctionType = @auctionType, 
    ReservationPrice = @reservationPrice, 
    MaxPrice = @maxPrice, 
    AuctionEnd = @auctionEnd, 
    AuctionStart = @auctionStart, 
    AuctionTTL = @auctionTTL 
    WHERE AuctionID = @auctionID; 

    UPDATE Item 
    SET 
    ItemName = @itemName, 
    ItemDescription = @itemDescription 
    WHERE 
    ItemID = (SELECT ItemID FROM Auction WHERE AuctionID = @auctionID); 

    COMMIT TRAN T1 

    RETURN @auctionID 
    END 
ELSE 
    BEGIN 
    BEGIN TRAN T1 
    INSERT INTO Item(ItemName, ItemDescription, CategoryID) 
    VALUES(@itemName, @itemDescription, @categoryID); 

    INSERT INTO Auction(ItemID, AuctionType, ReservationPrice, MaxPrice, AuctionEnd, AuctionStart, AuctionTTL) 
    VALUES(@@IDENTITY,@auctionType,@reservationPrice,@maxPrice,@auctionEnd,@auctionStart,@auctionTTL); 
    COMMIT TRAN T1 
    RETURN @@IDENTITY 
    END 

Y mi código es:

   cmd.CommandText = cmdText; 
       SqlParameter retval = new SqlParameter("@RETURN_VALUE", System.Data.SqlDbType.Int); 
       retval.Direction = System.Data.ParameterDirection.ReturnValue; 
       cmd.Parameters.Add(retval); 
       cmd.Parameters.AddRange(parameters); 
       cmd.Connection = connection; 

       connection.Open(); 
       cmd.ExecuteNonQuery(); 

       return (int)cmd.Parameters["@RETURN_VALUE"].Value; 
+0

Cuando dices 'vacío', ¿recibes una excepción que dice que el 'Valor' es nulo? (El elenco fallará si es nulo). ¿O es 0? –

+0

Su valor es 0. – WebMonster

+4

BTW, '@@ IDENTITY' es peligroso; deberías usar 'SCOPE_IDENTITY()' en su lugar. –

Respuesta

22

sólo trató en mi caja y esto funciona para mí:

En SQL Server:

DROP PROCEDURE TestProc; 
GO 
CREATE PROCEDURE TestProc 
AS 
    RETURN 123; 
GO 

En C#

 string cnStr = "Server=.;Database=Sandbox;Integrated Security=sspi;"; 
     using (SqlConnection cn = new SqlConnection(cnStr)) { 
      cn.Open(); 
      using (SqlCommand cmd = new SqlCommand("TestProc", cn)) { 
       cmd.CommandType = CommandType.StoredProcedure; 
       SqlParameter returnValue = new SqlParameter(); 
       returnValue.Direction = ParameterDirection.ReturnValue; 
       cmd.Parameters.Add(returnValue); 

       cmd.ExecuteNonQuery(); 
       Assert.AreEqual(123, (int)returnValue.Value); 
      } 
     } 
+0

id obtener el valor 0. – WebMonster

+0

He extendido el ejemplo. Quizás intentes esto. –

3

se obtiene el valor de que EXEC en TSQL? Me pregunto si la refactorización del TSQL ayudaría (y usando SCOPE_IDENTITY():

así cambiar:

COMMIT TRAN T1 
RETURN @@IDENTITY 

a:

SET @auctionID = SCOPE_IDENTITY() 
COMMIT TRAN T1 
RETURN @auctionID 

(que también cambiaría la otra @@IDENTITY a SCOPE_IDENTITY())


Como una optimización menor, También es posible usar:

return (int)retval.Value; 

pero este lado de las cosas debe haber trabajado "como es" de lo que puedo ver (por eso por lo que estoy centrado en el TSQL).

+0

Cambió lo que sugirió, pero no tuvo efecto. Uso "EXEC SetAuction @auctionID, ..." como CommandText. Obtengo el valor de retorno si lo ejecuto desde el explorador del servidor (Visual Studio). – WebMonster

4

I resuelto el problema: usted tiene que fijar SqlCommand.CommandType a CommandType.StoredProcedure para obtener valores de retorno y/o parámetros de salida. No he encontrado ninguna documentación sobre eso, pero ahora todo funciona.

1

Algunos también se puede utilizar este método simple y corto para calcular el valor de retorno de SP

En SQL:

Create Table TestTable 
(
Int Id 
) 

CREATE PROCEDURE Proc_TestProc 
@Id 
AS 
    Begin 
    Set NOCOUNT ON //Use this line if you don't want to return any message from SQL 

    Delete from TestTable where Id = @Id 
    return 1 

    Set NOCOUNT OFF //NOCOUNT OFF is Optional for NOCOUNT ON property 
    End 

SQL Server siempre devuelve el valor de tipo Int solamente.

y en C#

using (SqlConnection conn = new SqlConnection(System.Configuration.ConfigurationManager.ConnectionStrings["TestConnectionString"].ToString())) 
using (SqlCommand cmd = new SqlCommand("Proc_TestProc", conn)) 
{ 
cmd.CommandType = CommandType.StoredProcedure; 

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

conn.Open(); 
cmd.ExecuteNonQuery(); 
var result = returnParameter.Value; 
} 

También puede comprobar el valor de retorno de SQL mediante el uso de este comando:

DECLARE @return_status int; 
EXEC @return_status = dbo.[Proc_TestProc] 1; 
SELECT 'Return Status' = @return_status; 
print 'Returned value from Procedure: ' + Convert(varchar, @return_status); // Either previous or this line both will show you the value of returned value 
0

puede utilizar formas standart que se utilizan antes de las consultas normales, pero en el comando SQL, es necesario escribir EXEC antes de su tienda de nombre de procedimiento y no uso CommandType así:

SqlConnection con = new SqlConnection(["ConnectionString"]) 
    SqlCommand com = new SqlCommand("EXEC _Proc @id",con); 
    com.Parameters.AddWithValue("@id",["IDVALUE"]); 
    con.Open(); 
    SqlDataReader rdr = com.ExecuteReader(); 
    ArrayList liste = new ArrayList(); 
    While(rdr.Read()) 
    { 
    liste.Add(rdr[0]); //if it returns multiple you can add them another arrays=> liste1.Add(rdr[1]) .. 
    } 
    con.Close(); 
Cuestiones relacionadas