多次调用SetExecutionStrategy

时间:2019-04-16 09:41:26

标签: c# entity-framework

我正在尝试实现一个处理死锁并重试它们的实体框架配置。我的MyConfiguration构造函数中已经设置了默认执行策略。我的问题是,我可以一个接一个地打电话,还是会彼此优先?我对这些信息不是100%的自信,因此不胜感激。

如果我在MyConfiguration构造函数中同时使用两者,它们会相互覆盖还是会实际注册两者,因此两者都能工作?

代码如下:

public class MyConfiguration : DbConfiguration
{
    public MyConfiguration()
    {
        // Trims all strings coming from entity framework
        AddInterceptor(new StringTrimmerInterceptor());

        SetExecutionStrategy("System.Data.SqlClient", () => SuspendExecutionStrategy
          ? (IDbExecutionStrategy)new DefaultExecutionStrategy()
          : new SqlAzureExecutionStrategy());

        SetExecutionStrategy("System.Data.SqlClient", () => new MyCustomExecutionStrategy(5, TimeSpan.FromSeconds(10)));
    }

    public static bool SuspendExecutionStrategy
    {
        get
        {
            return (bool?)CallContext.LogicalGetData("SuspendExecutionStrategy") ?? false;
        }
        set
        {
            CallContext.LogicalSetData("SuspendExecutionStrategy", value);
        }
    }
}

public class StringTrimmerInterceptor : IDbCommandTreeInterceptor
{
    public void TreeCreated(DbCommandTreeInterceptionContext interceptionContext)
    {
        if (interceptionContext.OriginalResult.DataSpace == DataSpace.SSpace)
        {
            var queryCommand = interceptionContext.Result as DbQueryCommandTree;
            if (queryCommand != null)
            {
                var newQuery = queryCommand.Query.Accept(new StringTrimmerQueryVisitor());
                interceptionContext.Result = new DbQueryCommandTree(
                    queryCommand.MetadataWorkspace,
                    queryCommand.DataSpace,
                    newQuery);
            }
        }
    }

    private class StringTrimmerQueryVisitor : DefaultExpressionVisitor
    {
        private static readonly string[] _typesToTrim = { "nvarchar", "varchar", "char", "nchar" };

        public override DbExpression Visit(DbNewInstanceExpression expression)
        {
            var arguments = expression.Arguments.Select(a =>
            {
                var propertyArg = a as DbPropertyExpression;
                if (propertyArg != null && _typesToTrim.Contains(propertyArg.Property.TypeUsage.EdmType.Name))
                {
                    return EdmFunctions.Trim(a);
                }

                return a;
            });
            return DbExpressionBuilder.New(expression.ResultType, arguments);
        }
    }
}

public static class SqlRetryErrorCodes
{
    public const int TimeoutExpired = -2;
    public const int Deadlock = 1205;
    public const int CouldNotOpenConnection = 53;
    public const int TransportFail = 121;
}

public class MyCustomExecutionStrategy : DbExecutionStrategy
{
    public MyCustomExecutionStrategy(int maxRetryCount, TimeSpan maxDelay) : base(maxRetryCount, maxDelay) { }

    private readonly List<int> _errorCodesToRetry = new List<int>
        {
            SqlRetryErrorCodes.Deadlock,
            SqlRetryErrorCodes.TimeoutExpired,
            SqlRetryErrorCodes.CouldNotOpenConnection,
            SqlRetryErrorCodes.TransportFail
        };

    protected override bool ShouldRetryOn(Exception exception)
    {
        var sqlException = exception as SqlException;
        if (sqlException != null)
        {
            foreach (SqlError err in sqlException.Errors)
            {
                // Enumerate through all errors found in the exception.
                if (_errorCodesToRetry.Contains(err.Number))
                {
                    return true;
                }
            }
        }
        return false;
    }
}

1 个答案:

答案 0 :(得分:0)

从.NET团队的成员那里观察this post,每次调用该策略时,它都应覆盖该策略。链接显示甚至在运行时也可以更改(在每个ctor调用中)。在用法部分中,他指出:

  

现在,我们可以使用该标志为某些操作禁用重试逻辑。

所以,我的答案(未经证实)是:您可以多次调用它,并且始终会配置最后设置的策略。