Risposte:
Qui lo snippet di codice:
using System.Transactions;
....
using (var transactionScope = new TransactionScope())
{
DoYourDapperWork();
transactionScope.Complete();
}
Si noti che è necessario aggiungere un riferimento System.Transactions
all'assembly perché non è referenziato per impostazione predefinita.
Dispose()
metodo. Se Complete()
non è stato chiamato, la transazione viene annullata.
TransctionScope
blocco utilizzando nel caso in cui si scelga questa risposta.
Ho preferito utilizzare un approccio più intuitivo ottenendo la transazione direttamente dalla connessione:
// 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()
? In tal caso, questo metodo di estensione promuoverebbe un utilizzo errato della transazione. (IMO, dovrebbe persino lanciare "Impossibile aprire la transazione dopo che la connessione è già aperta".)
Execute
, poiché è necessario.
Dovresti essere in grado di usare TransactionScope
poiché Dapper esegue solo comandi ADO.NET.
using (var scope = new TransactionScope())
{
// insert
// insert
scope.Complete();
}
Considerando che tutte le tue tabelle sono in un unico database, non sono d'accordo con la TransactionScope
soluzione suggerita in alcune risposte qui. Riferisci questa risposta.
TransactionScope
è generalmente utilizzato per transazioni distribuite; le transazioni che si estendono su database diversi possono trovarsi su sistemi diversi. Ciò richiede alcune configurazioni sul sistema operativo e SQL Server senza le quali non funzionerà. Questa operazione non è consigliata se tutte le query riguardano una singola istanza del database.
Ma, con un database singolo, questo può essere utile quando è necessario includere il codice nella transazione che non è sotto il tuo controllo. Con un unico database, non necessita nemmeno di configurazioni speciali.
connection.BeginTransaction
è la sintassi di ADO.NET per implementare la transazione (in C #, VB.NET ecc.) su un singolo database. Non funziona su più database.
Così, connection.BeginTransaction()
è il modo migliore per andare.
Anche il modo migliore per gestire la transazione è implementare UnitOfWork come spiegato in questa risposta.
TransactionScope
inefficiente per ciò che vuole l'OP. Sono d'accordo che TransactionScope
in molti casi è un buon strumento; ma non questo.
La risposta di Daniel ha funzionato come previsto per me. Per completezza, ecco uno snippet che dimostra il commit e il rollback utilizzando un ambito di transazione e 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
metodo viene chiamato primo o secondo, solo che viene chiamato due volte. Quanto al punto che "chiamare smaltire una seconda volta non è dannoso", questo è un grande presupposto. Ho imparato che i documenti e le implementazioni effettive spesso non sono d'accordo. Ma se si vuole la parola di Microsoft per esso: msdn.microsoft.com/en-us/library/...