3

Does anyone know of any cases when using a transaction scope the transaction is escalated to the DTC when multiple connections are NOT open.

I am aware that if I open multiple connections(no matter what connection string) within a transaction scope that the transaction will most likely be promoted to the DTC.

Knowing this I have gone to great lengths to make sure there is only ONE connection opened within my transactions.

However, I have a client where they are getting the exception

An error has occurred. Csla.DataPortalException: DataPortal.Update failed (The underlying provider failed on Open.) ---> Csla.Reflection.CallMethodException: EditableCategory.DataPortal_Update method call failed ---> System.Data.EntityException: The underlying provider failed on Open. ---> System.Transactions.TransactionManagerCommunicationException: 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. ---> System.Runtime.InteropServices.COMException: The transaction manager has disabled its support for remote/network transactions.

Again, I am pretty sure there is only one connection opened within the scope. Take a look.

 protected override void DataPortal_Update()
    {
        using (System.Transactions.TransactionScope ts = new System.Transactions.TransactionScope(System.Transactions.TransactionScopeOption.Required, System.Transactions.TransactionManager.MaximumTimeout))
        {
            //get the dal manager he knows which dal implementation to use
            using (var dalMgr = DataAccess.BusinessObjectsDalFactory.GetManager())
            {
                //get the category dal implementation
                var ecDal = dalMgr.GetProvider<DataAccess.BusinessObjectDalInterfaces.ICategoryDAL>();

                //assume all the data is good at this point so use bypassproperty checks
                using (BypassPropertyChecks)
                {
                    var catData = new Models.Category { CategoryId = CategoryId, CategoryName = CategoryName, LastChanged = TimeStamp };

                    ecDal.UpdateCategory(catData);

                    TimeStamp = catData.LastChanged;
                }
            }

            ts.Complete();
        }

        base.DataPortal_Update();
    }

public class DalManager : Core.Sebring.DataAccess.IBusinessObjectsDalManager {private static string _typeMask = typeof(DalManager).FullName.Replace("DalManager", @"{0}");

public T GetProvider<T>() where T : class
{
  var typeName = string.Format(_typeMask, typeof(T).Name.Substring(1));
  var type = Type.GetType(typeName);
  if (type != null)
    return Activator.CreateInstance(type) as T;
  else
    throw new NotImplementedException(typeName);
}

public Csla.Data.DbContextManager<DataContext> ConnectionManager { get; private set; }

public DalManager()
{
    ConnectionManager = Csla.Data.DbContextManager<DataContext>.GetManager();
}

public void Dispose()
{
  ConnectionManager.Dispose();
  ConnectionManager = null;
}


public void UpdateDataBase()
{
    DatabaseUpgrader.PerformUpgrade();
}
}

 public void UpdateCategory(Models.Category catData)
    {
        if (catData == null) return;
        using (var cntx = DbContextManager<DataContext>.GetManager())
        {
            var cat = cntx.DbContext.Set<Category>().FirstOrDefault(c => c.CategoryId == catData.CategoryId);

            if (cat == null) return;

            if (!cat.LastChanged.Matches(catData.LastChanged))
                throw new ConcurrencyException(cat.GetType().ToString());

            cat.CategoryName = catData.CategoryName;
            //cntx.DbContext.ChangeTracker.DetectChanges();
            cntx.DbContext.Entry<Category>(cat).State = System.Data.EntityState.Modified;
            cntx.DbContext.SaveChanges();
            catData.LastChanged = cat.LastChanged;
        }

    }

The code for DBContextManager is available, but in short it just makes certain there is only one DBContext, and hence one connection opened. Am I overlooking something? I guess its possible that something is up with DBConextManager, so I have posted in the CSLA forums as well(DBContextManager is a part of CSLA). But has anyone run into scenarios where they are sure one connection is opened within the transaction scope and the transaction is escalated to the DTC?

Of course I cannot reproduce the exception on my local dev machine OR any of our QA machines.

Any help is appreciated.

Thanks.

ARs
  • 466
  • 1
  • 7
  • 14
  • 1
    Is it possible this is just a case of multiple instances of the application being open, and therefore multiple database connections? – Ryan Amies Aug 16 '13 at 17:39
  • Thanks for the suggestion. I didnt think about that. Although, Im pretty sure there was only one application instance open. I will check. Since I cannot reproduce and must shoot in the dark it may take a while for my to verify, but I will keep you posted. – ARs Aug 17 '13 at 15:57

1 Answers1

0

Entity Framework can randomly try to open a new connection when doing transactions with System.Transactions.TransactionScope

Try adding a finally statement and dispose your transaction, also call your dbContext and manually close the connection , this will lesser the ammount of times the transaction gets escalated but it might still happen:

finally
            {
                cntx.Database.Connection.Close();
                transaction.Dispose();
            }

Its a known "bug" you can find more here :

http://petermeinl.wordpress.com/2011/03/13/avoiding-unwanted-escalation-to-distributed-transactions/

  • Are you saying the sometimes EF 5 leaves a connection open? So there may be more than one connection opened withing the following? using(DataContex dc = new DataContext()){ //several selects,updates,deletes, inserts} – ARs Aug 19 '13 at 19:48
  • MaG3Stican was pretty much right. I asked this question http://stackoverflow.com/questions/18278994/transaction-escalated-to-dtc-no-multiple-connections then someone pointed me to the details, http://www.digitallycreated.net/Blog/48/entity-framework-transactionscope-and-msdtc, that ultimately answered my question. – ARs Aug 19 '13 at 21:37
  • Everytime you do a select or update EF5 opens a connection, might sometimes close it afterwards or might sometimes keep it open as long as the context is still alive. – Bryan Arbelo - MaG3Stican Aug 20 '13 at 15:13
  • Actually, its an issue of SQL Server 2005, TranscationScope, and EF5. No, connections were actually being left opened by EF not were they two different connections opened within the TransactionScope, but still the transaction was escalated to MSDTC. You can find the details of why here: http://www.digitallycreated.net/Blog/48/entity-framework-transactionscope-and-msdtc. I was able to reproduce the issue in my dev environment once I installed SQL Server 2005. Thanks for your help. – ARs Aug 20 '13 at 16:46