【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 ...
随机推荐
- scikit-learn主要模块和基本使用方法
从网上看到一篇总结的很不错的sklearn使用文档,备份勿忘. 引言 对于一些开始搞机器学习算法有害怕下手的小朋友,该如何快速入门,这让人挺挣扎的.在从事数据科学的人中,最常用的工具就是R和Pytho ...
- 倒计时,js
<!doctype html> <html> <head> <meta charset="utf-8"> <title> ...
- Linux 统计某个字符串出现的次数
要统计一个字符串出现的次数,这里现提供自己常用两种方法: 1. 使用vim统计 用vim打开目标文件,在命令模式下,输入 :%s/objStr//gn 即可 2. 使用grep: grep -o ob ...
- BW标准数据源初始化设置
在安装了一干补丁和做好了BW与R3的链接之后(此处有BISIS操心,具体事宜不详),我们就可以登录到R3系统看个究竟了. 磨刀不误砍柴工,先检查一下两边系统的补丁: R3端如下, ,貌似我们是19,通 ...
- 用git上传本地项目到github上
首先确认自己已经安装了git,打开git bash,输入ssh-keygen -t rsa -C "自己的邮箱地址@XXX.com" ,生成自己的公钥与私钥 一路默认回车,会生 ...
- iOS touch事件单击双击区分响应
如果您的 iPhone 应用里有个 view,既有单击操作又有双击操作.用户双击 view 时,总是先执行一遍单击的操作再执行双击的操作.所以直接判断时就会发现不能直接进入双击操作.下面是区分 tou ...
- 8个经典炫酷的HTML5 Canvas动画欣赏
HTML5非常强大,尤其是Canvas技术的应用,让HTML5几乎可以完成所有Flash能完成的效果.本文精选了8个经典炫酷的HTML5 Canvas动画欣赏,每一个都提供全部的源代码,希望对你有所帮 ...
- 关于STM32 CAN回环可用,正常不可用情况分析
1.回环下应该与GPIO无关 2.GPIO是否初始化正确,时钟启用 3.是否复用,AFIO时钟是否启用 4.回环下是否有CAN_Tx应该有输出 5.终端电阻是否有 6.CAN收发器电路电压是否正常 7 ...
- Apache MPM winnt
Win32DisableAcceptEx 指令在 apache2.4 被 AcceptFilter None 取代
- git merge之squash
看CM源码时,发现历史记录里有很多squash,于是google了解了一下. Git相对于CVS和SVN的一大好处就是merge非常方便,只要指出branch的名字就好了,如: 1 2 3 4 5 $ ...