Respostas:
Aqui está o snippet de código:
using System.Transactions;
....
using (var transactionScope = new TransactionScope())
{
DoYourDapperWork();
transactionScope.Complete();
}
Observe que você precisa adicionar referência ao System.Transactions
assembly porque ele não é referenciado por padrão.
Dispose()
método. Se Complete()
não tiver sido chamado, a transação será revertida.
TransctionScope
bloco de uso caso você escolha esta resposta.
Eu preferi usar uma abordagem mais intuitiva, obtendo a transação diretamente da conexão:
// 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()
? Se fosse esse o caso, esse método de extensão promoveria o uso incorreto da transação. (IMO, deve até lançar "não é possível abrir a transação depois que a conexão já estiver aberta".)
Execute
, pois isso é obrigatório.
Você deve ser capaz de usar, TransactionScope
já que o Dapper executa apenas comandos ADO.NET.
using (var scope = new TransactionScope())
{
// insert
// insert
scope.Complete();
}
Considerando que todas as suas tabelas estão em um único banco de dados, discordo da TransactionScope
solução sugerida em algumas respostas aqui. Consulte esta resposta.
TransactionScope
geralmente é usado para transações distribuídas; transações abrangendo bancos de dados diferentes podem estar em sistemas diferentes. Isso precisa de algumas configurações no sistema operacional e no SQL Server, sem as quais não funcionará. Isso não é recomendado se todas as suas consultas forem em uma única instância do banco de dados.
Mas, com um único banco de dados, isso pode ser útil quando você precisa incluir o código na transação que não está sob seu controle. Com um único banco de dados, também não precisa de configurações especiais.
connection.BeginTransaction
é a sintaxe ADO.NET para implementar a transação (em C #, VB.NET etc.) em um único banco de dados. Isso não funciona em vários bancos de dados.
Portanto, connection.BeginTransaction()
é o melhor caminho a percorrer.
Mesmo a melhor maneira de lidar com a transação é implementar UnitOfWork conforme explicado nesta resposta.
TransactionScope
que é ineficiente para o que o OP deseja. Concordo que TransactionScope
é uma boa ferramenta em muitos casos; mas não isso.
A resposta de Daniel funcionou conforme o esperado para mim. Para completar, aqui está um snippet que demonstra o commit e rollback usando um escopo de transação 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
método é chamado primeiro ou segundo, apenas que é chamado duas vezes. Quanto ao ponto de que "ligar para o descarte uma segunda vez não é prejudicial", é uma grande suposição. Aprendi que os documentos e as implementações reais muitas vezes não concordam. Mas se você quiser a palavra da Microsoft sobre isso: msdn.microsoft.com/en-us/library/…