我的项目中有一个旧的ObjectContext和几个新的DbContext(即用于不同目的的BoundedContext)。 有一段时间我需要在一次交易中从少数几个提交更改。在某些情况下,我需要保留ObjectContext和DbContext中的数据。 在EF 5.0中为了避免MSDC,我写了一些包装器
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();
}
});
};
}
}
}
但是在EntityFramework 6.0.1中它不起作用。 ObjectContext成功提交,但是当DbContext调用SaveChanges()时,带有文本的 EntityException 类型的异常 “基础提供商在EnlistTransaction 上失败。”内部Expection包含{“分布式事务管理器(MSDTC)的网络访问权限已被禁用。请使用组件服务管理工具在MSDTC的安全配置中启用DTC进行网络访问。”}
任何想法在一个事务中提交上下文并避免MDTC异常?
答案 0 :(得分:2)
您正尝试在本地事务中运行所有内容,即使使用相同类型的多个上下文也非常棘手。这样做的原因是您不能与同一本地事务建立多个打开的连接。如果前一个上下文仍然存在,通常会为下一个上下文打开一个新连接。这将触发将本地事务提升为分布式事务。
我对EF的体验是,当connectionstring(entityconnectionstring中的正常连接字符串)完全相同时,它只会重新使用当前连接。如果存在单一差异,则事务将提升到分布式事务,这必须由系统启用,在您的情况下,它不是。
此外,如果您已经在执行查询,并且仍在从该查询中读取结果,那么同时启动另一个查询将(当然)需要另一个连接,因此,本地事务将被提升为分布式事务。
您可以检查连接字符串是否相同吗?如果重新使用当前连接,我仍会感到惊讶。