La forma correcta de usar BeginTransaction con Dapper.IDbConnection

.net c# dapper idbconnection orm

Pregunta

¿Cuál es la forma correcta de usar BeginTransaction() con IDbConnection en Dapper?

BeginTransaction() un método en el que tengo que usar BeginTransaction() . Aquí está el código.

using (IDbConnection cn = DBConnection)
{
    var oTransaction = cn.BeginTransaction();

    try
    {
        // SAVE BASIC CONSULT DETAIL
        var oPara = new DynamicParameters();
        oPara.Add("@PatientID", iPatientID, dbType: DbType.Int32);
        ..........blah......blah............
    }
    catch (Exception ex)
    {
        oTransaction.Rollback();
        return new SaveResponse { Success = false, ResponseString = ex.Message };
    }
}

Cuando ejecuté el método anterior - obtuve una excepción -

Operación inválida. La conexión está cerrada.

Esto se debe a que no puede comenzar una transacción antes de que se abra la conexión. Entonces cuando agrego esta línea: cn.Open(); , el error se resuelve ¡Pero he leído en alguna parte que abrir manualmente la conexión es una mala práctica! Dapper abre una conexión solo cuando lo necesita.

En el marco de Entity puede manejar una transacción usando un TransactionScope .

Entonces mi pregunta es ¿cuál es una buena práctica para manejar transacciones sin agregar la línea cn.Open()... en Dapper ? Supongo que debería haber una forma adecuada para esto.

Respuesta aceptada

La apertura manual de una conexión no es una "mala práctica"; dapper funciona con conexiones abiertas o cerradas como una conveniencia , nada más. Un problema común es que las personas tienen conexiones que permanecen abiertas, sin usar, durante demasiado tiempo sin haberlas liberado nunca. Sin embargo, esto no es un problema en la mayoría de los casos, y sin duda se puede:

using(var cn = CreateConnection()) {
    cn.Open();
    using(var tran = cn.BeginTransaction()) {
        try {
            // multiple operations involving cn and tran here

            tran.Commit();
        } catch {
            tran.Rollback();
            throw;
        }
    }
}

Tenga en cuenta que dapper tiene un parámetro opcional para pasar en la transacción, por ejemplo:

cn.Execute(sql, args, transaction: tran);

En realidad, estoy tentado de hacer que los métodos de extensión en IDbTransaction funcionen de manera similar, ya que una transacción siempre expone .Connection ; esto permitiría:

tran.Execute(sql, args);

Pero esto no existe hoy.

TransactionScope es otra opción, pero tiene una semántica diferente: esto podría involucrar el LTM o el DTC, dependiendo de ... bueno, la suerte, principalmente. También es tentador crear un contenedor alrededor de IDbTransaction que no necesite el try / catch , más parecido a cómo funciona TransactionScope ; algo así como (esto tampoco existe):

using(var cn = CreateConnection())
using(var tran = cn.SimpleTransaction())
{
    tran.Execute(...);
    tran.Execute(...);

    tran.Complete();
}

Respuesta popular

No deberías llamar

cn.Close();

porque el bloque que usa intentará cerrarse también. Para la parte de transacción, sí, también puede usar TransactionScope, ya que no se trata de una técnica relacionada con Entity Framework. Eche un vistazo a esta respuesta SO: https://stackoverflow.com/a/6874617/566608 Explica cómo incluir su conexión en el alcance de la transacción. El aspecto importante es: la conexión se enlista automáticamente en la transacción IIF, se abre la conexión dentro del alcance .



Licencia bajo: CC-BY-SA with attribution
No afiliado con Stack Overflow
¿Es esto KB legal? Sí, aprende por qué
Licencia bajo: CC-BY-SA with attribution
No afiliado con Stack Overflow
¿Es esto KB legal? Sí, aprende por qué