Reputation: 31
I have an old ObjectContext and few new DbContext in my project (i.e. BoundedContext for different purposes). Some time I need to commit changes from few of them in one transactions. In some cases I need to persist data from ObjectContext and DbContext. In EF 5.0 to avoid of MSDC I write some wraper
public class ContextUnitOfWork
{
List<IContext> ContextList;
public ContextUnitOfWork()
{
ContextList = new List<IContext>();
}
public void RegisterContext(IContext Context)
{
ContextList.Add(Context);
}
public bool IsDisposed
{
get
{
return ContextList.Any(x => x.IsDisposed);
}
}
public bool HasChangedEntities
{
get
{
return ContextList.Any(x => x.HasChangedEntities);
}
}
public void Commit()
{
bool HasDbContext = ContextList.OfType<System.Data.Entity.DbContext>().Any();
try
{
if (HasDbContext)
{
ContextList.ForEach(x =>
{
if (x is System.Data.Entity.DbContext)
{
(x as System.Data.Entity.DbContext).Database.Connection.Open();
}
else if (x is System.Data.Objects.ObjectContext)
{
((System.Data.Objects.ObjectContext)x).Connection.Open();
}
});
}
using (var scope = new System.Transactions.TransactionScope(System.Transactions.TransactionScopeOption.Required,
new System.Transactions.TransactionOptions { IsolationLevel = System.Transactions.IsolationLevel.ReadCommitted }))
{
ContextList.ForEach(x => x.Commit());
scope.Complete();
}
}
catch (System.Data.UpdateException uex)
{
var ErrorList = uex.StateEntries.Select(x => x.Entity).ToList();
}
finally
{
if (HasDbContext)
{
ContextList.ForEach(x =>
{
if (x is System.Data.Entity.DbContext)
{
(x as System.Data.Entity.DbContext).Database.Connection.Close();
}
else if (x is System.Data.Objects.ObjectContext)
{
((System.Data.Objects.ObjectContext)x).Connection.Close();
}
});
};
}
}
}
But in EntityFramework 6.0.1 it doesn't work. ObjectContext commit successfully, but when DbContext call SaveChanges() an Exception of type EntityException with text "The underlying provider failed on EnlistTransaction." And Inner Expection contains {"Network access for Distributed Transaction Manager (MSDTC) has been disabled. Please enable DTC for network access in the security configuration for MSDTC using the Component Services Administrative tool."}
Any Idea to commit contexts in one transaction and avoid MDTC exception?
Upvotes: 1
Views: 837
Reputation: 22955
You are attempting to run everything in a local transaction which is very tricky even with multiple contexts of the same type. The reason for this is that you cannot have multiple open connections with the same local transaction. And very often a new connection will be opened for the next context if the previous context is still alive. This will trigger a promotion of the local transaction to a distributed transaction.
My experience with EF is that it only re-uses the current connection when the connectionstring (the normal one inside the entityconnectionstring) is EXACTLY identical. If there is a single difference, the transaction will be promoted to a distributed transaction, which must be enabled by the system, which in your case, it is not.
Also, if you are already executing a query, and are still reading results from that query, that starting another query at the same time, will (of course) require another connection, and therefore, the local transaction will be promoted to a distributed transaction.
Can you check if the connection strings are identical? I would still be surprised if current connection is re-used though.
Upvotes: 2