Reputation: 1236
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?
Upvotes: 2
Views: 2079
Reputation: 1684
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();
}
}
Upvotes: 2