事务已升级为DTC无多个连接

时间:2013-08-16 17:30:33

标签: c# entity-framework transactionscope msdtc csla

当使用事务范围时,有人知道任何情况,当多个连接未打开时,事务会升级到DTC。

我知道如果我在事务范围内打开多个连接(无论什么连接字符串),那么事务很可能会被提升为DTC。

知道了这一点,我已经竭尽全力确保在我的交易中只打开了一个连接。

但是,我有一个客户端,他们正在获得例外

发生了错误。 Csla.DataPortalException:DataPortal.Update失败(基础提供程序在Open上失败。)---> Csla.Reflection.CallMethodException:EditableCategory.DataPortal_Update方法调用失败---> System.Data.EntityException:基础提供程序在Open上失败。 ---> System.Transactions.TransactionManagerCommunicationException:已禁用分布式事务管理器(MSDTC)的网络访问。请使用组件服务管理工具在MSDTC的安全配置中启用DTC以进行网络访问。 ---> System.Runtime.InteropServices.COMException:事务管理器已禁用其对远程/网络事务的支持。

同样,我很确定在范围内只打开了一个连接。看一看。

 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;
        }

    }

DBContextManager的代码是可用的,但简而言之,它确保只有一个DBContext,因此打开了一个连接。我忽略了什么吗?我猜这可能是因为DBConextManager的问题,所以我也发布了CSLA论坛(DBContextManager是CSLA的一部分)。但是,有没有人遇到他们确信在交易范围内打开一个连接并且交易升级到DTC的情况?

当然,我无法在我的本地开发机器或任何QA机器上重现异常。

感谢任何帮助。

感谢。

1 个答案:

答案 0 :(得分:0)

实体框架可以在与System.Transactions.TransactionScope

进行交易时随机尝试打开新连接

尝试添加一个finally语句并处理你的事务,同时调用你的dbContext并手动关闭连接,这将减少事务升级的时间,但它可能仍然会发生:

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

这是一个已知的“错误”,你可以在这里找到更多:

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