Antworten:
Hier das Code-Snippet:
using System.Transactions;
....
using (var transactionScope = new TransactionScope())
{
DoYourDapperWork();
transactionScope.Complete();
}
Beachten Sie, dass Sie einen Verweis auf die System.Transactions
Assembly hinzufügen müssen, da standardmäßig nicht darauf verwiesen wird.
Dispose()
Methode. Wenn Complete()
nicht aufgerufen wurde, wird die Transaktion zurückgesetzt.
TransctionScope
Verwendungsblocks geöffnet werden, falls Sie diese Antwort wählen.
Ich habe es vorgezogen, einen intuitiveren Ansatz zu verwenden, indem ich die Transaktion direkt von der Verbindung erhalten habe:
// This called method will get a connection, and open it if it's not yet open.
using (var connection = GetOpenConnection())
using (var transaction = connection.BeginTransaction())
{
connection.Execute(
"INSERT INTO data(Foo, Bar) values (@Foo, @Bar);", listOf5000Items, transaction);
transaction.Commit();
}
.BeginTransaction()
haben? Wenn dies der Fall wäre, würde diese Erweiterungsmethode eine falsche Verwendung der Transaktion fördern. (IMO, es sollte sogar werfen "kann Transaktion nicht öffnen, nachdem die Verbindung bereits geöffnet ist".)
Execute
, da dies erforderlich ist.
Sie sollten in der Lage sein zu verwenden, TransactionScope
da Dapper nur ADO.NET-Befehle ausführt.
using (var scope = new TransactionScope())
{
// insert
// insert
scope.Complete();
}
Da sich alle Ihre Tabellen in einer einzigen Datenbank befinden, bin ich mit der TransactionScope
in einigen Antworten hier vorgeschlagenen Lösung nicht einverstanden . Verweisen Sie auf diese Antwort.
TransactionScope
wird im Allgemeinen für verteilte Transaktionen verwendet; Transaktionen, die sich über verschiedene Datenbanken erstrecken, können sich auf verschiedenen Systemen befinden. Dies erfordert einige Konfigurationen unter Betriebssystem und SQL Server, ohne die dies nicht funktioniert. Dies wird nicht empfohlen, wenn sich alle Ihre Abfragen auf eine einzelne Datenbankinstanz beziehen.
Bei einer einzelnen Datenbank kann dies jedoch hilfreich sein, wenn Sie den Code in eine Transaktion aufnehmen müssen, die nicht unter Ihrer Kontrolle steht. Bei einer einzelnen Datenbank sind auch keine speziellen Konfigurationen erforderlich.
connection.BeginTransaction
ist die ADO.NET-Syntax zum Implementieren von Transaktionen (in C #, VB.NET usw.) für eine einzelne Datenbank. Dies funktioniert nicht über mehrere Datenbanken hinweg.
Also, connection.BeginTransaction()
ist ein besserer Weg.
Noch besser ist es, UnitOfWork zu implementieren, wie in dieser Antwort erläutert .
TransactionScope
die für das, was OP will, ineffizient ist. Ich bin damit einverstanden, dass dies TransactionScope
in vielen Fällen ein gutes Werkzeug ist. aber nicht das.
Daniels Antwort funktionierte wie erwartet für mich. Der Vollständigkeit halber hier ein Ausschnitt, der Commit und Rollback anhand eines Transaktionsbereichs und eines Dappers demonstriert:
using System.Transactions;
// _sqlConnection has been opened elsewhere in preceeding code
using (var transactionScope = new TransactionScope())
{
try
{
long result = _sqlConnection.ExecuteScalar<long>(sqlString, new {Param1 = 1, Param2 = "string"});
transactionScope.Complete();
}
catch (Exception exception)
{
// Logger initialized elsewhere in code
_logger.Error(exception, $"Error encountered whilst executing SQL: {sqlString}, Message: {exception.Message}")
// re-throw to let the caller know
throw;
}
} // This is where Dispose is called
Dispose
Methode zuerst oder zweitens aufgerufen wird, nur dass sie zweimal aufgerufen wird. Was den Punkt betrifft, dass "ein zweites Mal Dispose nicht schädlich ist", ist dies eine große Annahme. Ich habe gelernt, dass die Dokumente und die tatsächlichen Implementierungen oft nicht übereinstimmen. Aber wenn Sie das Wort von Microsoft dafür wollen: msdn.microsoft.com/en-us/library/…