2012-04-28 23 views
80

Me gustaría ejecutar múltiples instrucciones de inserción en varias tablas. Estoy usando dapper.net. No veo ninguna forma de manejar transacciones con dapper.net.transacción con dapper dot net

Comparta sus ideas sobre cómo usar transacciones con dapper.net.

Respuesta

80

Aquí el fragmento de código:

using System.Transactions;  
....  
using (var transactionScope = new TransactionScope()) 
{ 
    DoYourDapperWork(); 
    transactionScope.Complete(); 
} 

Tenga en cuenta que es necesario agregar referencia a System.Transactions montaje, ya que no se hace referencia por defecto.

+2

¿Es necesario retrotraer explícitamente en error o System.Transactions maneja eso automáticamente? –

+2

@NorbertNorbertson lo hace automáticamente, en el método 'Dispose()'. Si no se ha llamado a 'Complete()', la transacción se retrotrae. –

15

Debería poder usar TransactionScope ya que Dapper solo ejecuta comandos ADO.NET.

using (var scope = new TransactionScope()) 
{ 
    // insert 
    // insert 
    scope.Complete(); 
} 
70

prefiero usar un enfoque más intuitivo por conseguir la transacción directamente desde la conexión:

// This 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(); 
} 
+0

@ANeves: Bueno, probablemente estamos usando diferentes frameworks Dapper, porque este tiene: https://github.com/StackExchange/dapper-dot-net – andrecarlucci

+13

tiene que llamar a connection.open() antes de iniciar una transacción – Timeless

+0

Una conexión no se alista automáticamente en transactionscope a menos que abra la conexión dentro del haz de transacciones. No sé cómo funciona tu código, si GetOpenConnection de alguna manera se abre mágicamente en el workscope, pero apostaría que no es –

4

respuesta de Daniel trabajó como se esperaba para mí. Para completar, aquí hay un fragmento que demuestra confirmar y deshacer el uso de un ámbito de transacción y pulcro:

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 
+2

@usr que se reduce a preferencia personal.Prefiero saber la primera vez que algo salió mal y no veo las declaraciones de registro como basura. Además, mi respuesta sigue siendo el valor de los anuncios al demostrar una forma de usar las transacciones con dapper – dotnetguy

+0

@CodeNaked, primero, tienes el orden equivocado allí. El bloque catch se golpeará primero si hay una excepción, luego el final del alcance para usar. En segundo lugar, observe esta respuesta y el documento MSDN referenciado: http: //stackoverflow.com/a/5306896/190476 llamando a disponer por segunda vez no es dañino, un objeto bien diseñado ignora la segunda llamada. ¡El voto abajo no está justificado! – dotnetguy

+0

@dotnetguy - No intenté comunicar qué método 'Dispose' se llama primero o segundo, solo que se llama dos veces. En cuanto al punto de que "llamar para disponer de una segunda vez no es perjudicial", esa es una gran suposición. Aprendí que los documentos y las implementaciones reales a menudo no concuerdan. Pero si quiere la palabra de Microsoft para esto: https://msdn.microsoft.com/en-us/library/ms182334.aspx?f=255&MSPPError=-2147217396 – CodeNaked

0

teniendo en cuenta todas las tablas están en la base de datos única, estoy de acuerdo con TransactionScope solución sugerida en algunas respuestas aquí. Consulte this respuesta.

  1. TransactionScope se usa generalmente para transacciones distribuidas; las transacciones que abarcan diferentes bases de datos pueden estar en sistemas diferentes. Esto necesita algunas configuraciones en el sistema operativo y SQL Server sin el cual esto no funcionará. Esto no se recomienda si todas sus consultas están en contra de una sola instancia de la base de datos.

  2. connection.BeginTransaction es la sintaxis de ADO.NET para implementar la transacción (en C#, VB.NET etc.) en una única base de datos. Esto no funciona en múltiples bases de datos.

Por lo tanto, connection.BeginTransaction() es mejor manera de hacerlo.

Incluso la mejor manera de manejar la transacción es implementar UnitOfWork como se explica en this answer.

+0

Uno no necesita múltiples bases de datos para beneficiarse de TransactionScope. De utilidad particular es que es ambiental. Es ideal para envolver código que no es de su propiedad o no puede modificar en una transacción. Por ejemplo, se puede usar con gran efecto cuando el código de prueba de la unidad/integración hace las llamadas a la base de datos donde desea retroceder. Simplemente haga flotar un TransactionScope, pruebe el código y deséchelo durante la limpieza de la prueba. –

+0

@LarrySmith: De acuerdo; pero la pregunta no es sobre nada de esto. OP solo dice que quiere insertar en varias tablas en una transacción. Algunas respuestas, incluida la aceptada, sugieren usar 'TransactionScope', que es ineficiente para lo que OP quiere. Acepto que 'TransactionScope' es una buena herramienta en muchos casos; pero no esto –