【发布时间】:2016-02-10 17:44:25
【问题描述】:
我有以下代码,旨在将批量 EF 保存分成更小的块,表面上是为了提高性能。
var allTasks = arrayOfConfigLists
.Select(configList =>
Task.Run(() => SaveConfigurations(configList))
.ToArray();
Task.WaitAll(allTasks);
对 SaveConfigurations 的每次调用都会创建一个运行到完成的新上下文。
private static void SaveConfigurations(List<Configuration> configs)
{
using (var dc = new ConfigContext())
{
dc.Configuration.AutoDetectChangesEnabled = false;
dc.SaveConfigurations(configs);
}
}
就目前而言,代码运行相对高效,考虑到这可能不是最佳的做事方式。但是,如果其中一个 SaveConfigurations 失败,我意识到我需要回滚保存到数据库的任何其他配置。
经过一些研究,我将现有框架升级到 4.5.1,并利用新的 TransactionScopeAsyncFlowOption.Enabled 选项来处理异步调用。我做了以下更改:
using (var scope =
new TransactionScope(TransactionScopeAsyncFlowOption.Enabled))
{
//... allTasks code snippet from above
scope.Complete();
}
此时,我开始汇总各种有趣的错误:
该操作对于事务的状态无效。
底层提供程序在打开时失败。
分布式事务管理器 (MSDTC) 的网络访问已被禁用。
事务管理器已禁用对远程/网络事务的支持。
我不明白为什么引入 TransactionScope 会产生这么多问题。我假设我对异步调用如何与 EF 交互以及 TransactionScope 如何包装这些调用存在根本性的误解,但我无法弄清楚。而且我真的不知道 MSDTC 异常与什么有关。
关于如何通过对同一个数据库进行异步调用来实现回滚功能有什么想法吗?有没有更好的方法来处理这种情况?
更新: 查看文档here 后,我发现 Database.BeginTransaction() 是首选的 EF 调用。但是,这假设我的所有更改都将发生在同一上下文中,但事实并非如此。没有创建一个虚拟上下文和传递一个事务,我认为这不能解决我的问题。
【问题讨论】:
标签: c# entity-framework asynchronous transactions rollback