簡體   English   中英

我的自定義 DbExecutionStrategy 沒有被調用

[英]My custom DbExecutionStrategy is not being called

我最初的問題是我在更新 SQL 數據庫時經常遇到死鎖。 通過一點點研究,我發現我可以定義一個自定義 DbConfiguration 和一個 DbExecutionStrategy,它指示實體框架在 x 毫秒和 y 次后出現某些錯誤后自動重試。 太棒了!

因此,按照https://msdn.microsoft.com/en-us/data/jj680699 上的指南,我構建了正在使用的自定義 DbConfiguration,但相關的 DbExecutionStrategy 似乎被忽略了。

最初,我的整個 DbConfiguration 都被忽略了,但我發現這是因為我在 app.config 中引用了它,並使用 DbConfigurationType 屬性 [DbConfigurationType(typeof(MyConfiguration))] 裝飾了我的實體構造函數。 現在我只使用 app.config,至少我的自定義配置正在被調用。

以最簡單的形式,我的自定義配置如下所示:

public class MyConfiguration : DbConfiguration
{
    public MyConfiguration()
    {
        System.Windows.MessageBox.Show("Hey! Here I am!"); //I threw this in just to check that I was calling the constructor. Simple breakpoints don't seem to work here.
        SetExecutionStrategy("System.Data.SqlClient", () => new MyExecutionStrategy(3, TimeSpan.FromMilliseconds(500)));
    }
}

我的自定義 DbConfiguration 在我的 app.config 中被引用,如下所示:

<entityFramework codeConfigurationType="MyDataLayer.MyConfiguration, MyDataLayer">
    ...
</entityFramework>

我的自定義 DbExecutionStrategy 是這樣構建的:

private class MyExecutionStrategy : DbExecutionStrategy
{
    public MyExecutionStrategy() : this(3, TimeSpan.FromSeconds(2))
    {
        System.Windows.MessageBox.Show($"MyExecutionStrategy instantiated through default constructor.");
    }

    public MyExecutionStrategy(int maxRetryCount, TimeSpan maxDelay) : base(maxRetryCount, maxDelay)
    {
        System.Windows.MessageBox.Show($"MyExecutionStrategy instantiated through parametered constructor.");
    }

    protected override bool ShouldRetryOn(Exception ex)
    {
        System.Windows.MessageBox.Show($"Overriding ShouldRetryOn.");

        bool retry = false;

        SqlException sqlException = GetSqlException(ex);

        if (sqlException != null)
        {
            int[] errorsToRetry =
            {
                1205,  //Deadlock
                -2     //Timeout
            };

            if (sqlException.Errors.Cast<SqlError>().Any(x => errorsToRetry.Contains(x.Number)))
            {
                retry = true;
            }
        }

        if (ex is TimeoutException)
        {
            retry = true;
        }

        return retry;
    }
}

在這段特定的代碼中,我根本沒有遇到任何問題。

可能值得注意的一件事是,到目前為止我看到的每個例子(例如http://blog.analystcircle.com/2015/08/01/connection-resiliency-in-entity-framework-6-0 -and-above/ ) 已使用將 ShouldRetryOn 中的異常直接轉換為 SqlException

SqlException sqlException = ex as SqlException;

我發現使用這種方法總是會導致一個空的 SqlException,因為我的程序拋出了一個無法轉換為 SqlException 的 EntityException。 我的底層SqlException其實就是EntityException內部異常的內部異常。 所以,我整理了一個簡短的遞歸調用來深入挖掘並找到它。

private SqlException GetSqlException(Exception ex)
{
    SqlException result = ex as SqlException;

    if (result == null && ex.InnerException != null)
        result = GetSqlException(ex.InnerException);

    return result;
}

這工作正常,但是當我發現的示例沒有時我需要這樣做的事實可能是關於出了什么問題的線索。 EntityExceptions 不會觸發 DbExecutionStrategy 嗎? 如果不是,為什么將其列為與 EF 6 一起使用的解決方案? 任何見解將不勝感激。

編輯:進一步挖掘 DbExecutionStrategy 的源代碼( https://github.com/aspnet/EntityFramework6/blob/master/src/EntityFramework/Infrastructure/DbExecutionStrategy.cs ),我發現我的遞歸函數可以找到我的EntityException 中的 SqlException 是不必要的。 DbExecutionStrategy 有一個 UnwrapAndHandleException 函數,它就是這樣做的,並將 SqlException 傳遞給 ShouldRetryOn。 所以,看來我又回到了第一站。

編輯 2:不是真正的解決方案,因為它沒有解釋為什么我的 DbExecutionStrategy 沒有被調用,但我發現如果我顯式調用執行策略,它就可以工作。

顯式使用執行策略的代碼是:

var executionStrategy = new MyConfiguration.MyExecutionStrategy();

executionStrategy.Execute(
    () =>
    {
        //build your context and execute db functions here
        using (var context = new Entities())
        {
            ...do stuff
        }
    });

現在可能太老了,但以防萬一有人遇到同樣的問題:

  • exception.GetBaseException() 為您提供任何異常的根本原因。 不需要遞歸

  • 我可以使用 EF 6.4.0 讓它工作

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM