【EF 译文系列】重试执行策略的局限性(EF 版本至少为 6)
原文链接:Limitations with Retrying Execution Strategies (EF6 onwards)
当使用重试执行策略的时候,大体有以下两种局限性:
不支持以流的方式进行查询
默认情况下,EF 6 或以后的版本,都是使用缓冲的方式而不是流的方式进行查询。如果你想使用以流的方式进行查询,可以使用 AsStreaming 方法来改变 LINQ to Entities 的默认查询方式:
using (var db = new BloggingContext())
{
var query = (from b in db.Blogs
orderby b.Url
select b).AsStreaming();
}
重试执行策略不支持以流的方式来进行查询,因为连接中可能会丢失掉部分的返回信息,而 EF 并不能确定哪些是已经正确返回了(数据可能在查询执行后被改变了,返回信息的顺序可能是不一定的,返回信息也可能没有一个唯一标识),所以无法进行有效的重试执行。
不支持用户手动启动的事务
当你配置了重试执行策略时,对于使用事务是有一定限制的。
怎样是被支持的:EF 默认的事务机制
默认情况下,EF 对数据库进行更新操作时,都会自动的建立在一个事务里,你无需额外的做些什么来开启它。
举个例子,下面代码中的 SavaChanges 会自动的执行在一个事务中,当插入数据中的任何一条失败,事务都会回滚,从而不会对数据库进行任何更改,这时上下文中也会有一个状态来允许 SavaChanges 进行重试操作。
using (var db = new BloggingContext())
{
db.Blogs.Add(new Site { Url = "http://msdn.com/data/ef" });
db.Blogs.Add(new Site { Url = "http://www.cnblogs.com/prinsun/" });
db.SaveChanges();
}
怎样是不被支持的:用户手动开启的事务
当不使用重试执行策略的时候,用户可以将多个操作包裹到一个事务中。如下面的代码中,在一个事务中包裹了两个 SavaChanges ,当其中任何一个失败,数据库中都不会有任何记录产生。
using (var db = new BloggingContext())
{
using (var trn = db.Database.BeginTransaction())
{
db.Blogs.Add(new Site { Url = "http://msdn.com/data/ef" });
db.Blogs.Add(new Site { Url = "http://www.cnblogs.com/prinsun/" });
db.SaveChanges(); db.Blogs.Add(new Site { Url = "http://twitter.com/efmagicunicorns" });
db.SaveChanges(); trn.Commit();
}
}
当使用重试执行策略的时候,这样的操作是不受支持的。因为 EF 无法知道任何先前的操作,以至于无法去重试它们。比如,如果上诉的第二个 SavaChanges 失败了,EF 没有办法去尝试重新执行第一个 SavaChanges。
变通的方式
挂起执行策略
一种可行的变通方案便是在需要手动开启事务的时候,暂时的挂起重试执行策略。最简单的实现方法便是在执行策略的配置类中加入一个是否挂起的标识,并在执行策略的 lambda 表达式中用该标识做一个判定:
using System.Data.Entity;
using System.Data.Entity.Infrastructure;
using System.Data.Entity.SqlServer;
using System.Runtime.Remoting.Messaging; namespace Demo
{
public class MyConfiguration : DbConfiguration
{
public MyConfiguration()
{
this.SetExecutionStrategy("System.Data.SqlClient", () => SuspendExecutionStrategy
? (IDbExecutionStrategy)new DefaultExecutionStrategy()
: new SqlAzureExecutionStrategy());
} public static bool SuspendExecutionStrategy
{
get
{
return (bool?)CallContext.LogicalGetData("SuspendExecutionStrategy") ?? false;
}
set
{
CallContext.LogicalSetData("SuspendExecutionStrategy", value);
}
}
}
}
注意,我们使用了 CallContext 来存储这样的一个标识,这是为了这个值能和调用线程有关,能够安全的支持异步或多线程下的查询(即不会影响到其它线程中的策略执行)。
现在我们可以在需要手动开启事务的时候,使用挂起策略的这个功能了:
using (var db = new BloggingContext())
{
MyConfiguration.SuspendExecutionStrategy = true; using (var trn = db.Database.BeginTransaction())
{
db.Blogs.Add(new Site { Url = "http://msdn.com/data/ef" });
db.Blogs.Add(new Site { Url = "http://www.cnblogs.com/prinsun/" });
db.SaveChanges(); db.Blogs.Add(new Site { Url = "http://twitter.com/efmagicunicorns" });
db.SaveChanges(); trn.Commit();
} MyConfiguration.SuspendExecutionStrategy = false;
}
手动调用执行策略
另外一个选择便是手动的来执行重试策略,我们需要给相应的策略提供重试的执行逻辑,这样它才可以在操作失败时进行有效的重试。为了防止配置中的策略干扰,我们仍然需要将其挂起。
注意,所有的 Context 都需要在重试的代码块中进行实例化,这样才可以确保在每一次的重试操作中所有模型的状态是正确的:
var executionStrategy = new SqlAzureExecutionStrategy(); MyConfiguration.SuspendExecutionStrategy = true; executionStrategy.Execute(
() =>
{
using (var db = new BloggingContext())
{
using (var trn = db.Database.BeginTransaction())
{
db.Blogs.Add(new Site { Url = "http://msdn.com/data/ef" });
db.Blogs.Add(new Site { Url = "http://www.cnblogs.com/prinsun/" });
db.SaveChanges(); db.Blogs.Add(new Site { Url = "http://twitter.com/efmagicunicorns" });
db.SaveChanges(); trn.Commit();
}
}
}); MyConfiguration.SuspendExecutionStrategy = false;
【EF 译文系列】重试执行策略的局限性(EF 版本至少为 6)的更多相关文章
- Entity Framework 6 暂停重试执行策略
EF6引入一个弹性连接的功能,也就是允许重新尝试执行失败的数据库操作.某些复杂的场景中,可能需要启用或停用重试执行的策略,但是EF框架暂时尚未提供直接的设置开关,将来可能会加入这种配置.幸运的是,很容 ...
- 【EF 译文系列】韧性连接、重试(EF 版本至少为 6)
原文链接:Connection Resiliency / Retry Logic (EF6 onwards) 一个应用程序的数据库连接,是非常容易受其它因素影响的,比如后端的异常或者不稳定的网络连接等 ...
- 【EF 译文系列】模型和数据库连接
原文链接:Connections and Models 本篇文章主要包括 Entity Framework 是如何选择数据库进行连接,以及我们如何去改变它的连接.无论是通过 Code First 还 ...
- EF CodeFirst系列(6)---配置1对1,1对多,多对多关系
这一节介绍EF CodeFirst模式中的1对0/1,1对多,多对多关系的配置,只有梳理清楚实体间的关系,才能进行愉快的开发,因此这节虽然很简单但是还是记录了一下. 1. 1对0/1关系配置 1. 通 ...
- EF CodeFirst系列(9)---添加初始化数据和数据库迁移策略
1.添加初始化数据(Seed) 我们可以在初始化数据库的过程中给数据库添加一些数据.为了实现初始化数据(seed data)我们必须创建一个自定义的数据库初始化器(DB initializer),并重 ...
- 7.翻译系列:EF 6中的继承策略(EF 6 Code-First 系列)
原文地址:http://www.entityframeworktutorial.net/code-first/inheritance-strategy-in-code-first.aspx EF 6 ...
- EF 学习系列三 数据操作数据加载及EF中执行Sql
1.实体状态 我们通过EF来对数据库进行操作并持久化到数据库,那么EF必然通过EF上下文来维护实体的状态,明确知道每一个状态所对应的操作.也就是说EF通过上下文负责跟踪实体的状态.EF实体状态存在命名 ...
- 20.1翻译系列:EF 6中自动数据迁移技术【EF 6 Code-First系列】
原文链接:https://www.entityframeworktutorial.net/code-first/automated-migration-in-code-first.aspx EF 6 ...
- 16.翻译系列:EF 6 Code -First中使用存储过程【EF 6 Code-First系列】
原文链接:https://www.entityframeworktutorial.net/entityframework6/code-first-insert-update-delete-stored ...
随机推荐
- Android酷炫实用的开源框架——UI框架(转)
转载别人整理好的文章,列出了很多炫酷的UI开源设计 原文地址:http://www.androidchina.net/1992.html 1.Side-Menu.Android分类侧滑菜单,Yalan ...
- 在ps中画两个同心圆并且把两个同心圆进行任意角度切割
在工作中遇到要在ps中画如图两个同心圆,并且进行6等分.查找资料加自己摸索,可以通过以下方式实现: 1.新建一画布.并用通过标尺画出两条水平和垂直参考线,选择椭圆工具,并在选项设置中选择圆和从中心两个 ...
- 菜鸟教程之工具使用(十四)——Maven项目右击没有“Maven”菜单选项
从Git导入一个Maven项目,右击想更新Maven引用的jar包,却发现右键菜单根本没有“Maven”菜单项.怎么办?很简单,按如下步骤操作即可: 从Git导入后,右击项目没有“Maven”菜单项: ...
- wordpress自动保存远程图片插件 DX-auto-save-images
wordpress自动保存远程图片插件DX-auto-save-images 解决了保存文章就可以自动将远程图片保存到你的服务器上了. 具体操作步骤如下: 1.安装启用wordpress自动保存远程图 ...
- web端视频直播网站的弊端和优势
在YY上市前后,国内涌出一批类YY视频直播或9158的秀场类网站. 比如六间房,酷六等等 这种web端视频服务基本依靠web本身的特性,用flash直播,靠CDN提供服务. 但是这样的架构有2个问题 ...
- zendStudio 10.5破解
1.下载zendStudio 10.5(mac系统) windows系统安装文件 并安装. 2.下载破解文件,并覆盖安装目录plugins同名文件,要注意版本. 3.启动程序,输入注册码: 3 ...
- android中的layoutparams参数使用的简单总结
定义: 我们可以在Android的framework中的ViewGroup类里找到定义的类: public static class LayoutParams{...} 此类有如下注释: Layout ...
- JAVA本地远程连接linux程序监控状态
环境: 1.本地window 2.程序部署在centos 一,启动访问权限安全守护程序 新建文件:jstatd.all.policy ,注意路径 grant codebase "$JA ...
- swift 闭包
闭包可以捕获和存储其所在上下文中任意常量和变量的引用. 这就是所谓的闭合并包裹着 这些常量和变量,俗称闭包. Swift标准库中提供了sort排序函数,sort函数的第二个参数是个闭包.和OC中的bl ...
- ART:Android 摆脱卡顿的希望?
与 iOS 相比,Android 的用户体验有个相对糟糕的开始.在很长的时间里,界面一直丑小鸭,卡顿也是挥不去的痛.不过,在 Google 的全力推动,以及硬件厂商的响应下,Android 还是跨越各 ...