Return value of ExecuteNonQuery after rollback

后端 未结 1 731
醉话见心
醉话见心 2020-12-31 04:18

Assuming that we have a stored procedure that does like something this:

BEGIN TRANSACTION
    UPDATE sometable SET aField = 0 WHERE anotherField = 1;       
         


        
相关标签:
1条回答
  • 2020-12-31 04:45

    It appears that the return value of ExecuteNonQuery is unaffected by a rollback even though the documentation clearly states that is does. Here are some possible workarounds.

    1) Use ExecuteScalar

    SP:

    DECLARE @RowCount INT
    DECLARE @Error INT
    
    BEGIN TRAN
    
    UPDATE Table1 SET Value1 = NULL
    
    SELECT @RowCount = @@ROWCOUNT, @Error = @@ERROR
    
    IF @Error <> 0 BEGIN
        ROLLBACK TRAN
        SELECT -1
    END ELSE BEGIN
        COMMIT TRAN
        SELECT @RowCount
    END
    

    C#

    using (SqlConnection dbConnection = new SqlConnection("Data Source=.;Initial Catalog=Database1;Integrated Security=True;MultipleActiveResultSets=True"))
    {
        dbConnection.Open();
    
        using (SqlCommand command = dbConnection.CreateCommand())
        {
            command.CommandText = "QuickTest";
            command.CommandType = CommandType.StoredProcedure;
    
            rowsAffected = command.ExecuteScalar();
        }
    }
    

    2) Use a return/output parameter

    SP: DECLARE @RowCount INT DECLARE @Error INT

    BEGIN TRAN
    
    UPDATE Table1 SET Value1 = NULL
    
    SELECT @RowCount = @@ROWCOUNT, @Error = @@ERROR
    
    IF @Error <> 0 BEGIN
        ROLLBACK TRAN
        RETURN -1
    END ELSE BEGIN
        COMMIT TRAN
        RETURN @RowCount
    END
    

    C#

    using (SqlConnection dbConnection = new SqlConnection("Data Source=.;Initial Catalog=Database1;Integrated Security=True;MultipleActiveResultSets=True"))
    {
        dbConnection.Open();
    
        using (SqlCommand command = dbConnection.CreateCommand())
        {
            command.Parameters.Add(new SqlParameter() {Direction = ParameterDirection.ReturnValue });
            command.CommandText = "QuickTest";
            command.CommandType = CommandType.StoredProcedure;
    
            command.ExecuteNonQuery();
            rowsAffected = command.Parameters[0].Value;
        }
    }
    

    3) Move the rollback/commit logic into the code

    This would give you the ability to determine if a rollback occurred and output a value of -1 when necessary. The transaction statement would need to removed from the sproc.

    SP:

    UPDATE Table1 SET Value1 = NULL
    

    C#:

    using (SqlConnection dbConnection = new SqlConnection("Data Source=.;Initial Catalog=Database1;Integrated Security=True;MultipleActiveResultSets=True"))
    {
        dbConnection.Open();
    
        using (SqlTransaction tran = dbConnection.BeginTransaction())
        {
            using (SqlCommand command = dbConnection.CreateCommand())
            {
                command.Transaction = tran;
    
                try
                {
                    command.Parameters.Add(new SqlParameter() {Direction = ParameterDirection.ReturnValue });
                    command.CommandText = "QuickTest";
                    command.CommandType = CommandType.StoredProcedure;
    
                    rowsAffected = command.ExecuteNonQuery();
                }
    
                catch (Exception)
                {
                    rowsAffected = -1;
                    throw;
                }
    
                tran.Commit();
            }
        }
    }
    

    As noted previously, the @@ROWCOUNT value and the ExecuteNonQuery result are both affected by triggers.

    0 讨论(0)
提交回复
热议问题