C# 事务升级到DTC无多个连接

C# 事务升级到DTC无多个连接,c#,entity-framework,transactionscope,msdtc,csla,C#,Entity Framework,Transactionscope,Msdtc,Csla,是否有人知道在使用交易范围时,当多个连接未打开时,交易升级到DTC 我知道,如果我在一个事务范围内打开多个连接(无论连接字符串是什么),该事务很可能会升级为DTC 知道这一点,我已经竭尽全力确保在我的事务中只打开一个连接 然而,我有一个客户,他们得到了例外 发生了一个错误。Csla.DataPortalException:DataPortal.Update失败(基础提供程序在打开时失败。)-->Csla.Reflection.CallMethodException:EditableCograph

是否有人知道在使用交易范围时,当多个连接未打开时,交易升级到DTC

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

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

然而,我有一个客户,他们得到了例外

发生了一个错误。Csla.DataPortalException:DataPortal.Update失败(基础提供程序在打开时失败。)-->Csla.Reflection.CallMethodException:EditableCography.DataPortalU更新方法调用失败---->System.Data.EntityException:基础提供程序在打开时失败。-->System.Transactions.TransactionManager通信异常:已禁用分布式事务管理器(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;
        }

    }
protected override void DataPortal_Update()
{
使用(System.Transactions.TransactionScope ts=new System.Transactions.TransactionScope(System.Transactions.TransactionScopeOption.Required,System.Transactions.TransactionManager.MaximumTimeout))
{
//让dal经理知道要使用哪个dal实现
使用(var dalMgr=DataAccess.BusinessObjectsDalFactory.GetManager())
{
//获取类别dal实现
var ecDal=dalMgr.GetProvider();
//假设此时所有数据都很好,因此使用绕过属性检查
使用(绕过属性检查)
{
var catData=new Models.Category{CategoryId=CategoryId,CategoryName=CategoryName,LastChanged=TimeStamp};
ecDal.UpdateCategory(catData);
TimeStamp=catData.LastChanged;
}
}
ts.完成();
}
base.DataPortal_Update();
}
公共类DalManager:Core.Sebring.DataAccess.IBusinessObjectsDalManager{private static string_typeMask=typeof(DalManager).FullName.Replace(“DalManager”,@{0}”);
public T GetProvider(),其中T:class
{
var typeName=string.Format(_typeMask,typeof(T).Name.Substring(1));
var type=type.GetType(typeName);
if(type!=null)
将Activator.CreateInstance(类型)返回为T;
其他的
抛出新的NotImplementedException(typeName);
}
public Csla.Data.DbContextManager连接管理器{get;private set;}
公共事务经理()
{
ConnectionManager=Csla.Data.DbContextManager.GetManager();
}
公共空间处置()
{
ConnectionManager.Dispose();
ConnectionManager=null;
}
public void UpdateDataBase()
{
DatabaseUpgrader.PerformUpgrade();
}
}
public void UpdateCategory(Models.Category catData)
{
if(catData==null)返回;
使用(var cntx=DbContextManager.GetManager())
{
var cat=cntx.DbContext.Set().FirstOrDefault(c=>c.CategoryId==catData.CategoryId);
如果(cat==null)返回;
如果(!cat.LastChanged.Matches(catData.LastChanged))
抛出新的ConcurrencyException(cat.GetType().ToString());
cat.CategoryName=catData.CategoryName;
//cntx.DbContext.ChangeTracker.DetectChanges();
cntx.DbContext.Entry(cat.State=System.Data.EntityState.Modified;
cntx.DbContext.SaveChanges();
catData.LastChanged=cat.LastChanged;
}
}
DBContextManager的代码是可用的,但简而言之,它只是确保只有一个DBContext,因此打开了一个连接。我是不是忽略了什么?我想可能是DBConextManager出了什么问题,所以我也在CSLA论坛上发了帖子(DBContextManager是CSLA的一部分)。但是,是否有人遇到过这样的情况:他们确信在事务范围内打开了一个连接,并且事务升级到DTC

当然,我不能在本地开发机器或任何QA机器上复制异常

感谢您的帮助


谢谢。

当使用
System.transactions.TransactionScope进行交易时,实体框架可以随机尝试打开新连接

尝试添加finally语句并处理事务,同时调用dbContext并手动关闭连接,这将减少事务升级的次数,但仍有可能发生:

finally
            {
                cntx.Database.Connection.Close();
                transaction.Dispose();
            }
这是一个已知的“bug”,您可以在此处找到更多信息:


这是否可能只是应用程序的多个实例被打开,从而导致多个数据库连接?谢谢您的建议。我没有想到这一点。不过,我很确定只有一个应用程序实例处于打开状态。我查一下。由于我无法复制,必须在黑暗中拍摄,我的验证可能需要一段时间,但我会随时通知你。你是说有时EF 5会打开连接吗?因此,可能会有多个连接在以下情况下打开?使用(DataContex dc=newdatacontext()){//几个选择、更新、删除、插入}MaG3Stican非常正确。我问了这个问题,然后有人向我指出了详细信息,这最终回答了我的问题。每次执行选择或更新EF5时,都会打开一个连接,有时会在之后关闭它,有时可能会在上下文仍然存在时保持它打开。实际上,这是SQL Server 2005、TransactionScope和EF5的问题。不,连接实际上是不可靠的