2013-02-25 10 views
17

Unter der Annahme, dass wir eine gespeicherte Prozedur, die wie etwas tut dieses:Rückgabewert von ExecuteNonQuery nach Rollback

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

Und von C# haben wir so etwas wie dieses:

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();     
} 

Warum ich nicht bin bekomme ich Res == -1? Ich bekomme immer noch die Anzahl der betroffenen Zeilen. Wenn in der Dokumentation steht: "If a rollback occurs, the return value is also -1"

Was fehlt mir hier?

+2

Was ist der Wert von res? – Peter

+0

@peer in diesem Fall würde es 2. Die Anzahl der betroffenen Zeilen – coffeeyesplease

+0

Interessanterweise wenn Sie nur diesen Code in SSMS ausführen, erhalten Sie "1 Zeile (n) betroffen" oder ähnlich. (Oder 2, oder was auch immer - aber nicht 0, obwohl es zurückgerollt wird.) – Rawling

Antwort

1

Es scheint, dass der Rückgabewert ExecuteNonQuery von einem Rollback nicht betroffen ist, obwohl die Dokumentation eindeutig angibt, dass dies der Fall ist. Hier sind einige mögliche Problemumgehungen.

1) Verwenden 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) Mit einem Rücklauf/Ausgabeparameter

SP: DECLARE @RowCount INT ERKLÄREN @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) Bewegen Sie den Rollback/Commit-Logik in den Code

Thi Mit s können Sie feststellen, ob ein Rollback aufgetreten ist, und bei Bedarf einen Wert von -1 ausgeben. Die Transaktionsanweisung müsste aus dem Sproc entfernt werden.

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(); 
     } 
    } 
} 

Wie bereits erwähnt, die @@ ROWCOUNT-Wert und die ExecuteNonQuery Ergebnis werden beide von Trigger betroffen.

+0

Eine Sache zu beachten ist, dass, wenn es einen Trigger gibt - diese Zeilen werden hinzugefügt - so muss das OP auch auf diese achten. –

+0

Hallo. Danke, aber das ist nicht das, wonach ich suche. Ich möchte die Anzahl der betroffenen Zeilen, wenn die Abfrage in Ordnung geht. Wie ich will -1 wenn nicht. Wenn ich NO COUNT ON setze, bekomme ich immer -1 als Ergebnis von ExecuteNonQuery – coffeeyesplease

+0

Und das ist nicht, was die Dokumentation sagt. Darin heißt es: "Bei UPDATE-, INSERT- und DELETE-Anweisungen ist der Rückgabewert die Anzahl der vom Befehl betroffenen Zeilen. Wenn ein Trigger für eine einzufügende oder aktualisierte Tabelle vorhanden ist, enthält der Rückgabewert die Anzahl der Zeilen, die von der Einfügung betroffen sind oder Aktualisierungsvorgang und die Anzahl der Zeilen, die vom Trigger oder den Triggern betroffen sind. Bei allen anderen Statementtypen ist der Rückgabewert -1. Wenn ein Rollback auftritt, ist der Rückgabewert ebenfalls -1. " – coffeeyesplease