回滚后返回ExecuteNonQuery的值

cof*_*ase 17 .net c# stored-procedures sqlclient

假设我们有一个存储过程就像这样:

BEGIN TRANSACTION
    UPDATE sometable SET aField = 0 WHERE anotherField = 1;       
    UPDATE sometable SET aField = 1 WHERE anotherField = 2;
ROLLBACK TRANSACTION;
Run Code Online (Sandbox Code Playgroud)

从C#我们有这样的事情:

using (var connection = new SqlConnection("connection string")) 
{
    connection.Open();
    var cmd = connection.CreateCommand();
    cmd.CommandType = CommandType.StoredProcedure;
    cmd.CommandText = "my_procedure";
    var res = cmd.ExecuteNonQuery();                
}
Run Code Online (Sandbox Code Playgroud)

为什么我没有得到res == -1?我仍然得到受影响的行数.当文档声明"如果发生回滚,返回值也为-1"

我在这里缺少什么?

Sac*_*ege 1

看起来 的返回值ExecuteNonQuery不受回滚的影响,尽管文档明确指出会受到回滚的影响。以下是一些可能的解决方法。

1) 使用执行标量

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
Run Code Online (Sandbox Code Playgroud)

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();
    }
}
Run Code Online (Sandbox Code Playgroud)

2) 使用返回/输出参数

SP: 声明@RowCount INT 声明@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
Run Code Online (Sandbox Code Playgroud)

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;
    }
}
Run Code Online (Sandbox Code Playgroud)

3)将回滚/提交逻辑移至代码中

这将使您能够确定是否发生回滚并在必要时输出值 -1。事务语句需要从存储过程中删除。

SP:

UPDATE Table1 SET Value1 = NULL
Run Code Online (Sandbox Code Playgroud)

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();
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

如前所述,@@ROWCOUNT 值和 ExecuteNonQuery 结果均受触发器影响。