Respuestas:
Aquí el fragmento de código:
using System.Transactions;
....
using (var transactionScope = new TransactionScope())
{
DoYourDapperWork();
transactionScope.Complete();
}
Tenga en cuenta que debe agregar una referencia al System.Transactions
ensamblado porque no se hace referencia a él de forma predeterminada.
Dispose()
método. Si Complete()
no se ha llamado, la transacción se revierte.
TransctionScope
bloque de uso en caso de que elija esta respuesta.
Preferí usar un enfoque más intuitivo obteniendo la transacción directamente desde la conexión:
// 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()
? Si ese fuera el caso, este método de extensión promovería el uso incorrecto de la transacción. (OMI, aún debe lanzar "no puede transacción abierta después de la conexión ya está abierta".)
Execute
, ya que es obligatorio.
Debería poder usarlo, TransactionScope
ya que Dapper solo ejecuta comandos ADO.NET.
using (var scope = new TransactionScope())
{
// insert
// insert
scope.Complete();
}
Teniendo en cuenta que todas sus tablas están en una sola base de datos, no estoy de acuerdo con la TransactionScope
solución sugerida en algunas respuestas aquí. Consulte esta respuesta.
TransactionScope
se utiliza generalmente para transacciones distribuidas; la transacción que abarca diferentes bases de datos puede estar en un sistema diferente. Esto necesita algunas configuraciones en el sistema operativo y SQL Server sin las cuales esto no funcionará. Esto no se recomienda si todas sus consultas están relacionadas con una sola instancia de la base de datos.
Pero, con una sola base de datos, esto puede ser útil cuando necesita incluir el código en una transacción que no está bajo su control. Con una única base de datos, tampoco necesita configuraciones especiales.
connection.BeginTransaction
es la sintaxis de ADO.NET para implementar transacciones (en C #, VB.NET, etc.) contra una sola base de datos. Esto no funciona en varias bases de datos.
Entonces, connection.BeginTransaction()
es una mejor manera de hacerlo.
Incluso la mejor manera de manejar la transacción es implementar UnitOfWork como se explica en esta respuesta.
TransactionScope
cuál es ineficiente para lo que OP quiere. Estoy de acuerdo en que TransactionScope
es una buena herramienta en muchos casos; pero no esto.
La respuesta de Daniel funcionó como se esperaba para mí. Para completar, aquí hay un fragmento que demuestra la confirmación y la reversión usando un alcance de transacción y elegante:
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 se llama primero o segundo, solo que se llama dos veces. En cuanto al punto de que "llamar a desechar por segunda vez no es perjudicial", es una gran suposición. He aprendido que los documentos y las implementaciones reales a menudo no concuerdan. Pero si desea la palabra de Microsoft para ello: msdn.microsoft.com/en-us/library/…