原文链接: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)的更多相关文章

  1. Entity Framework 6 暂停重试执行策略

    EF6引入一个弹性连接的功能,也就是允许重新尝试执行失败的数据库操作.某些复杂的场景中,可能需要启用或停用重试执行的策略,但是EF框架暂时尚未提供直接的设置开关,将来可能会加入这种配置.幸运的是,很容 ...

  2. 【EF 译文系列】韧性连接、重试(EF 版本至少为 6)

    原文链接:Connection Resiliency / Retry Logic (EF6 onwards) 一个应用程序的数据库连接,是非常容易受其它因素影响的,比如后端的异常或者不稳定的网络连接等 ...

  3. 【EF 译文系列】模型和数据库连接

    原文链接:Connections and Models 本篇文章主要包括 Entity Framework  是如何选择数据库进行连接,以及我们如何去改变它的连接.无论是通过 Code First 还 ...

  4. EF CodeFirst系列(6)---配置1对1,1对多,多对多关系

    这一节介绍EF CodeFirst模式中的1对0/1,1对多,多对多关系的配置,只有梳理清楚实体间的关系,才能进行愉快的开发,因此这节虽然很简单但是还是记录了一下. 1. 1对0/1关系配置 1. 通 ...

  5. EF CodeFirst系列(9)---添加初始化数据和数据库迁移策略

    1.添加初始化数据(Seed) 我们可以在初始化数据库的过程中给数据库添加一些数据.为了实现初始化数据(seed data)我们必须创建一个自定义的数据库初始化器(DB initializer),并重 ...

  6. 7.翻译系列:EF 6中的继承策略(EF 6 Code-First 系列)

    原文地址:http://www.entityframeworktutorial.net/code-first/inheritance-strategy-in-code-first.aspx EF 6 ...

  7. EF 学习系列三 数据操作数据加载及EF中执行Sql

    1.实体状态 我们通过EF来对数据库进行操作并持久化到数据库,那么EF必然通过EF上下文来维护实体的状态,明确知道每一个状态所对应的操作.也就是说EF通过上下文负责跟踪实体的状态.EF实体状态存在命名 ...

  8. 20.1翻译系列:EF 6中自动数据迁移技术【EF 6 Code-First系列】

    原文链接:https://www.entityframeworktutorial.net/code-first/automated-migration-in-code-first.aspx EF 6 ...

  9. 16.翻译系列:EF 6 Code -First中使用存储过程【EF 6 Code-First系列】

    原文链接:https://www.entityframeworktutorial.net/entityframework6/code-first-insert-update-delete-stored ...

随机推荐

  1. Oracle 11g导入导出命令

    首先需要进入系统的cmd: 执行导出命令,效果如下 expdp hisjk/hisjk@orcl  directory=DATA_PUMP_DIR dumpfile=hisjk.dmp SCHEMAS ...

  2. web开发必备-网络基础知识---记录一下

    1.osi 7层网络模型 2.socket 套接字编程 PS:一个从事web开发的人来说,我们是使用http协议来和服务器来进行交互.后面会详细的分析这个过程.

  3. 【LeetCode】263. Ugly Number

    Ugly Number Write a program to check whether a given number is an ugly number. Ugly numbers are posi ...

  4. dwz_bootstrap + thinkphp

    http://www.thinkphp.cn/code/936.html  回去继续学习 SuperWebSocket

  5. Hadoop2.x源码-编译剖析

    1.概述 最近,有小伙伴涉及到源码编译.然而,在编译期间也是遇到各种坑,在求助于搜索引擎,技术博客,也是难以解决自身所遇到的问题.笔者在被询问多次的情况下,今天打算为大家来写一篇文章来剖析下编译的细节 ...

  6. Gamma校正与线性工作流

    1 Gamma校正是什么?8位亮度值x(0-1)经过x^0.45的一个提亮过程. 2 为什么需要Gamma校正 人的眼睛是以非线性方式感知亮度,在自然界中,人感觉到的一半亮度其实只有全部能量的0.2, ...

  7. 即将放出ITSEC第一期所有培训视频

    课程大概被分为三个章节 客户端安全培训 安全工具培训 服务端安全培训   部分PPT                         详细课程表 FireBug代码调试工具使用:工具介绍 FireBu ...

  8. 高性能优化Web前端

    高性能HTML 一.避免使用iframe iframe也叫内联frame,可将一个HTML文档嵌入另一个HTML文档中. iframe的好处是,嵌入的文档独立于父文档,通常也借此使浏览器模拟多线程.缺 ...

  9. android自定义RadioGroup实现可以添加多种布局

    android自带的RadioGroup是继承自LinearLayout,如果布局的时候不是直接写radiobutton,即radiobutton外面还包了一层容器,这时分组是不成功的,因为查找不到r ...

  10. JQM[jquery mobile] 实战经验汇总

    动态装载的子页面(data-role=”page”),完全不用page div之外的tag,也不会起作用.子页面的javascript脚本必须写在page的</div>之前. 切换按钮(a ...