【问题标题】:Configuring resiliency settings Entity Framework 6.02配置弹性设置实体框架 6.02
【发布时间】:2014-01-31 15:29:17
【问题描述】:

我正在尝试为 EF6.02 配置弹性设置。我有一个应用程序,它在一个执行点将日志条目写入数据库。应用程序不依赖于 SQL 服务器,因此如果服务器没有响应,我希望应用程序放弃 INSERT 查询(通过 DbContext 的 SaveChanges)并立即继续执行。

使用默认设置,调试日志输出十个

“System.Data.dll 中发生了‘System.Data.SqlClient.SqlException’类型的第一次机会异常”

十次尝试后,它抛出一个异常,我的代码继续。但我只想要一次尝试,例如 2 秒命令超时。根据 MSDN 上的文档,SQL 服务器的默认弹性方法是:

DefaultSqlExecutionStrategy这是默认使用的内部执行策略。此策略根本不会重试,但是,它将包装任何可能是暂时的异常,以通知用户他们可能希望启用连接弹性。

正如文档所述,此策略根本不会重试。但我仍然有十次重试。我试图创建一个继承 DbConfiguration 的类,但我没有找到任何关于如何更改它的文档。

谁能帮我减少重试次数?

更新:以下是基于建议的代码

using System;
using System.Data.Entity;
using System.Data.Entity.SqlServer;
using System.Data.Entity.Infrastructure;
using System.Runtime.Remoting.Messaging;

namespace MyDbLayer
{
    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);
            }
        } 
    }
}

以及写入 SQL 的代码

try
    {
        using (MyEntities context = new MyEntities ())
        {
            Log logEntry = new Log();
            logEntry.TS = DateTime.Now;

            MyConfiguration.SuspendExecutionStrategy = true;
            context.Log.Add(logEntry);
            context.SaveChanges();
        }
    }
    catch (Exception ex)
    {
        logger.Warn("Connection error with database server.", ex);
    }
    finally
    {
        //Enable retries again...
        MyConfiguration.SuspendExecutionStrategy = false;
    }

【问题讨论】:

    标签: c# sql .net database entity-framework


    【解决方案1】:

    你试过execution strategy suspension吗?

    您自己的数据库配置应该是这样的:

    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); 
            } 
        } 
    } 
    

    那么你可以像这样定义不可重试的命令:

    public static void ExecWithoutRetry(System.Action action)
    {
        var restoreExecutionStrategyState = EbgDbConfiguration.SuspendExecutionStrategy;
        try
        {
            MyConfiguration.SuspendExecutionStrategy = true;
            action();
        }
        catch (Exception)
        {
            // ignore any exception if we want to
        }
        finally
        {
            MyConfiguration.SuspendExecutionStrategy = restoreExecutionStrategyState;
        }
    }
    

    最后,带有可重试和不可重试命令的常规数据库代码可能如下所示:

    using (var db = new MyContext())
    {
        ExecWithoutRetry(() => db.WriteEvent("My event without retries"));
        db.DoAnyOperationWithRetryStrategy();
    }
    

    【讨论】:

    • 感谢您的帮助。是否需要所有这些代码来减少 Entity Framework 6 中的连接重试次数? (!)
    • @ElToro,也许我误解了你的问题。如果要禁用所有 SQL 命令的重试,则只需更改 MyConfiguration 构造函数,如下所示:this.SetExecutionStrategy("System.Data.SqlClient", () => new DefaultExecutionStrategy()。我的解决方案仅对代码编写事件的特定部分禁用重试。
    • 不,你从一开始就是对的。我只是对复杂程度感到震惊(即使你的代码很漂亮)。我虽然可能有更简单的方法。例如:“context.Connection.NumberOfExecutionRetries = 0”。但是非常感谢!
    • 我已经用ExecWithoutRetry() 方法包装了不可重试的命令,以获得更清晰的逻辑流程。我自己就是这样做的,不幸的是我无法找到另一种更短的方法来组合可重试和不可重试命令。
    • 奇怪,我刚试了你的原始代码,仍然执行了多次重试......
    【解决方案2】:

    我找到了。我只需要在连接字符串中添加“Connection Timeout=X”,其中 X 是秒,一切正常,无需修改 ExecutionStrategies 等。

    在执行查询之前添加它解决了它

    contextInstance.Database.Connection.ConnectionString = context.Database.Connection.ConnectionString + ";Connection Timeout=2;";
    

    【讨论】:

    • 您不应在代码中附加到连接字符串。而是更改连接字符串本身。您的代码违背了动态配置的整个概念,使您的应用配置不直观。
    • 因为我对不同的查询使用了不同的超时时间,所以我无法看到如何在配置文件中更改连接字符串。
    猜你喜欢
    • 2010-10-03
    • 2012-11-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多