我的自定义DbExecutionStrategy没有被调用 [英] My custom DbExecutionStrategy is not being called
问题描述
我最初的问题是更新SQL数据库时经常遇到死锁。经过一番研究,我发现我可以定义一个自定义DbConfiguration以及一个DbExecutionStrategy,它指示Entity Framework在x毫秒和y次重复出现某些错误后自动重试。太棒了!
My original problem was that I was experiencing deadlocks often when updating my SQL database. Through a little bit of research, I found that I'm able to define a custom DbConfiguration and with it a DbExecutionStrategy which instructs Entity Framework to automatically retry after getting certain errors after x milliseconds and y number of times. Great!
因此,请按照 https://msdn.microsoft.com/zh-cn/data/jj680699 ,我构建了正在使用的自定义DbConfiguration,但似乎忽略了相关的DbExecutionStrategy。
So, following the guide at https://msdn.microsoft.com/en-us/data/jj680699, I build my custom DbConfiguration, which is being used, but the associated DbExecutionStrategy seems to be ignored.
最初,我的整个DbConfiguration被忽略了,但是我发现这是因为我在app.config中引用了它,以及用DbConfigurationType属性[DbConfigurationType(typeof(MyConfiguration ))]。现在,我仅使用app.config,至少调用了我的自定义配置。
Originally, my entire DbConfiguration was being ignored, but I found that was because I was referencing it in my app.config as well as decorating my entity constructor with the DbConfigurationType attribute [DbConfigurationType(typeof(MyConfiguration))]. Now that I'm only using the app.config, at least my custom configuration is being called.
最简单的形式是,我的自定义配置如下:
In its simplest form, my custom config looks like this:
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)));
}
}
在我的app.config中引用了我的自定义DbConfiguration,例如因此:
My custom DbConfiguration is referenced in my app.config like so:
<entityFramework codeConfigurationType="MyDataLayer.MyConfiguration, MyDataLayer">
...
</entityFramework>
我的自定义DbExecutionStrategy的构建方式如下:
My custom DbExecutionStrategy is built like so:
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;
}
}
在这个特殊情况下我什么都没打这段代码。
I'm not hitting anything at all in this particular piece of the code.
可能要注意的一件事是,到目前为止,我见过的每个示例(例如 http://blog.analystcircle.com/2015/08 / 01 / connection-resiliency-in-entity-framework-6-0-and-above / )已将ShouldRetryOn中的异常直接使用
One thing that may be of note, is that every example I've seen so far (for example http://blog.analystcircle.com/2015/08/01/connection-resiliency-in-entity-framework-6-0-and-above/) has casted the exception in ShouldRetryOn directly to a SqlException using
SqlException sqlException = ex as SqlException;
我发现使用此方法始终会导致空SqlException,因为我的程序抛出了EntityException,不会被强制转换为SqlException。我的基础SqlException实际上是EntityException内部异常的内部异常。因此,我整理了一个简短的递归调用以进行挖掘并找到它。
I found that using this method always resulted in a null SqlException because my program is throwing an EntityException which can't be cast into a SqlException. My underlying SqlException is actually the inner exception of the inner exception of the EntityException. So, I put together a short recursive call to dig in and find it.
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一起使用的解决方案?
This works properly, but the fact that I need to do it when the examples I've found don't is probably a clue as to what's going wrong. Do EntityExceptions not trigger a DbExecutionStrategy? If not, why is this listed as a solution to be used with EF 6? Any insight would be much appreciated.
编辑:
为DbExecutionStrategy( https://github.com/aspnet/EntityFramework6/blob/master/src/ EntityFramework / Infrastructure / DbExecutionStrategy.cs ),我发现不需要从EntityException中找到SqlException的递归函数。 DbExecutionStrategy具有一个函数UnwrapAndHandleException,该函数可以将SqlException传递给ShouldRetryOn。因此,看来我又回到了第一个方格。
Doing some more digging into the source for DbExecutionStrategy (https://github.com/aspnet/EntityFramework6/blob/master/src/EntityFramework/Infrastructure/DbExecutionStrategy.cs), I've found that my recursive function to find my SqlException from the EntityException is unnecessary. DbExecutionStrategy has a function UnwrapAndHandleException which does just that and passes the SqlException on to ShouldRetryOn. So, it seems I'm right back at square one.
编辑2:
并不是一个解决方案,因为它没有并没有解释为什么未按应有的方式调用我的DbExecutionStrategy,但是我发现,如果我明确调用执行策略,它就会起作用。
EDIT 2: Not really a solution, because it doesn't explain why my DbExecutionStrategy isn't being called as it should, but I have found that if I explicitly call the execution strategy, it works.
要使用的代码执行策略明确为:
The code to use the execution strategy explicitly is:
var executionStrategy = new MyConfiguration.MyExecutionStrategy();
executionStrategy.Execute(
() =>
{
//build your context and execute db functions here
using (var context = new Entities())
{
...do stuff
}
});
推荐答案
现在可能太老了,但如果有人具有相同的问题:
Probably way too old by now but in case anyone is having the same issues:
-
exception.GetBaseException()使您产生任何异常的根本原因。不需要递归
exception.GetBaseException() gets you the root cause of any exception. No need for recursion
我能够使用EF 6.4.0
I'm able to get this to work using EF 6.4.0
这篇关于我的自定义DbExecutionStrategy没有被调用的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!