Odpowiedzi:
Tutaj fragment kodu:
using System.Transactions;
....
using (var transactionScope = new TransactionScope())
{
DoYourDapperWork();
transactionScope.Complete();
}
Zauważ, że musisz dodać odwołanie do System.Transactions
zestawu, ponieważ domyślnie nie ma do niego odwołania.
Dispose()
metodą. Jeśli Complete()
nie został wywołany, transakcja zostanie wycofana.
TransctionScope
bloku using w przypadku wybrania tej odpowiedzi.
Wolałem zastosować bardziej intuicyjne podejście, pobierając transakcję bezpośrednio z połączenia:
// 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()
go? Gdyby tak było, ta metoda rozszerzenia promowałaby niewłaściwe wykorzystanie transakcji. (IMO, powinno nawet wyrzucić „nie można otworzyć transakcji po tym, jak połączenie jest już otwarte”.)
Execute
, ponieważ jest to wymagane.
Powinieneś móc używać, TransactionScope
ponieważ Dapper uruchamia tylko polecenia ADO.NET.
using (var scope = new TransactionScope())
{
// insert
// insert
scope.Complete();
}
Biorąc pod uwagę, że wszystkie twoje tabele znajdują się w jednej bazie danych, nie zgadzam się z TransactionScope
rozwiązaniem sugerowanym w niektórych odpowiedziach tutaj. Skorzystaj z tej odpowiedzi.
TransactionScope
jest zwykle używany do transakcji rozproszonych; transakcja obejmująca różne bazy danych może znajdować się w innym systemie. Wymaga to pewnych konfiguracji w systemie operacyjnym i SQL Server, bez których to nie zadziała. Nie jest to zalecane, jeśli wszystkie zapytania dotyczą jednej instancji bazy danych.
Ale w przypadku jednej bazy danych może to być przydatne, gdy musisz uwzględnić kod w transakcji, nad którym nie masz kontroli. W przypadku pojedynczej bazy danych nie wymaga również specjalnych konfiguracji.
connection.BeginTransaction
to składnia ADO.NET do implementacji transakcji (w C #, VB.NET itp.) w pojedynczej bazie danych. Nie działa to w przypadku wielu baz danych.
Więc connection.BeginTransaction()
jest lepszym sposobem.
Jeszcze lepszym sposobem obsługi transakcji jest wdrożenie UnitOfWork, jak wyjaśniono w tej odpowiedzi.
TransactionScope
co jest nieefektywne dla tego, czego chce PO. Zgadzam się, że TransactionScope
to dobre narzędzie w wielu przypadkach; ale nie to.
Odpowiedź Daniela zadziałała dla mnie zgodnie z oczekiwaniami. Dla kompletności, oto fragment, który demonstruje zatwierdzanie i wycofywanie przy użyciu zakresu transakcji i dapper:
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
metoda jest wywoływana jako pierwsza czy druga, tylko że jest wywoływana dwukrotnie. Co do tego, że „wezwanie do pozbycia się po raz drugi nie jest szkodliwe”, to duże założenie. Dowiedziałem się, że dokumenty i rzeczywiste implementacje często nie są zgodne. Ale jeśli chcesz na to słowo Microsoftu: msdn.microsoft.com/en-us/library/ ...