3

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

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

知道这一点后,我竭尽全力确保在我的事务中只打开一个连接。

但是,我有一个客户,他们遇到了异常

发生了错误。Csla.DataPortalException:DataPortal.Update 失败(底层提供程序在打开时失败。)---> Csla.Reflection.CallMethodException:EditableCategory.DataPortal_Update 方法调用失败---> System.Data.EntityException:底层提供程序在打开时失败。---> 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 机器上重现异常。

任何帮助表示赞赏。

谢谢。

4

1 回答 1

0

Entity Framework 可以在进行事务时随机尝试打开一个新连接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/

于 2013-08-16T18:31:23.817 回答