Transaction per request in multiple dbcontext in EntityFramework

asp.net-mvc c# entity-framework-6 transactions

Question

I'm using Asp.Net MVC and Entity Framework. I have a class to manage transaction per request as follow:

public class TransactionPerRequest :
    IRunOnEachRequest, IRunOnError, IRunAfterEachRequest
{
    private readonly ContextDB _Context;
    private readonly HttpContextBase _HttpContext;

    public TransactionPerRequest(ContextDB context,
        HttpContextBase httpContext)
    {
        _Context = context;
        _HttpContext = httpContext;
    }

    void IRunOnEachRequest.Execute()
    {
        _HttpContext.Items["_Transaction"] =
            _Context.Database.BeginTransaction(IsolationLevel.ReadCommitted);
    }

    void IRunOnError.Execute()
    {
        _HttpContext.Items["_Error"] = true;
    }

    void IRunAfterEachRequest.Execute()
    {
        var transaction = (DbContextTransaction)_HttpContext.Items["_Transaction"];

        if (_HttpContext.Items["_Error"] != null)
            transaction.Rollback();
        else
            transaction.Commit();
    }
}

I want to use multiple contexts as explained here

How I can change the TransactionPerRequset class?

1
3
3/5/2018 1:07:46 PM

Accepted Answer

I have done this,

The crucial thing is to take control of database connection life-cycle away from EF, and take care of connection initialization, opening, closing and disposal yourself.

To do this, you will use following base DbContext constructor :DbContext(DbConnection connection, Boolean contextOwnsConnection)

Constructs a new context instance using the existing connection to connect to a database. The connection will not be disposed when the context is disposed if contextOwnsConnection is false.

You should expose constructor with DbConnection in all your application contexts and inject same connection you created outside DbContext. This way EF will not create and open them.

Finally, in your connection manager class you can use DbConnection.BeginTransaction() to get DbTransaction object and work with it according to your needs.

Below is draft of required changes of your class, to get the idea across.

public partial class ContextDB : DbContext
{
    // New constructor
    public ContextDB(DbConnection connection)
        : base(connection, false)
    {
    }
}

public class TransactionPerRequest :
    IRunOnEachRequest, IRunOnError, IRunAfterEachRequest
{
    private readonly ContextDB _Context;
    private readonly HttpContextBase _HttpContext;
    private readonly DbConnection _cnn;

    public TransactionPerRequest(HttpContextBase httpContext)
    {
        // Your code creates the connection
        _cnn = new SqlConnection("Data Source=.;Initial Catalog=DB;Integrated Security=SSPI;");
        // Pass connection your context
        _Context = new ContextDB(_cnn);
        _HttpContext = httpContext;
    }

    void IRunOnEachRequest.Execute()
    {
        // Open connection
        _cnn.Open();
        _HttpContext.Items["_Transaction"] =
            _cnn.BeginTransaction(IsolationLevel.ReadCommitted);
    }

    void IRunOnError.Execute()
    {
        _HttpContext.Items["_Error"] = true;
    }

    void IRunAfterEachRequest.Execute()
    {
        var transaction = (DbContextTransaction)_HttpContext.Items["_Transaction"];

        if (_HttpContext.Items["_Error"] != null)
            transaction.Rollback();
        else
            transaction.Commit();

        _cnn.Close();
        _cnn.Dispose();
    }
}
2
12/4/2016 11:11:12 AM


Related Questions





Related

Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow
Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow