Я пытаюсь выполнить повторные попытки для моих соединений с базой данных, которые я заработал, но это также нарушает инициируемые пользователем транзакции, которые у меня есть.
В частности, я вижу такие ошибки:
Настроенная стратегия выполнения RetryExecutionStrategy не поддерживает инициируемые пользователем транзакции. См. http://go.microsoft.com/fwlink/?LinkId=309381 для получения дополнительной информации.
Я бы очень хотел реализовать первый обходной путь от Microsoft , но даже второго было бы достаточно. Несмотря на множество попыток с разных сторон, мне не удалось заставить вещи работать на транзакции. Я пробовал искать существующие вопросы в StackOverflow (и в остальном интернете, правда), но безрезультатно. Возможно, решения, которые я нашел в другом месте, работают для отдельных потоков с одним соединением за раз, но я работаю над большим проектом, в котором транзакции и нетранзакции происходят в непредсказуемом порядке.
В конечном счете, мне нужен способ отключения повторных попыток транзакций или исправление, позволяющее избежать сбоя транзакций при включенной повторной попытке.
Что у меня есть для моего DbContext:
[DbConfigurationType("MyNamespace.RetryConfiguration","MyNamespace")]
public partial class RepoContext : DbContext {
public RepoContext(string entityConnectionString) : base(entityConnectionString)
{
}
}
Моя RetryExecutionStrategy:
public class RetryExecutionStrategy : DbExecutionStrategy
{
public RetryExecutionStrategy(int maxRetries, TimeSpan maxDelay)
: base(maxRetries, maxDelay)
{
}
protected override bool ShouldRetryOn(Exception e)
{
return true;
}
}
Моя RetryConfiguration:
public class RetryConfiguration : DbConfiguration
{
public RetryConfiguration()
{
var executionStrategy = SuspendExecutionStrategy
? (IDbExecutionStrategy)new DefaultExecutionStrategy()
: new RetryExecutionStrategy(3, new TimeSpan(0, 0, 0, 3));
this.SetExecutionStrategy("Devart.Data.PostgreSql", () => executionStrategy);
}
public static bool SuspendExecutionStrategy
{
get
{
return (bool?)CallContext.LogicalGetData("SuspendExecutionStrategy") ?? false;
}
set
{
CallContext.LogicalSetData("SuspendExecutionStrategy", value);
}
}
}
Если я что-то упустил, я думаю, что правильно применил пример Microsoft. Исходя из моего понимания их примера, EF должен создавать новый экземпляр RetryConfiguration для каждого вызова репо. В противном случае их пример не имеет никакого смысла, поскольку он только когда-либо создаст соединение с RetryExecutionStrategy, а не DefaultExecutionStrategy, который необходим для инициируемых пользователем транзакций. В противоположность этому, я установил точку останова на конструкторе RetryConfiguration и обнаружил, что он создается только один раз.
Это привело к многочисленным головным болям и попыткам выполнить их второй обходной путь, подобный следующему:
var res = new RetryExecutionStrategy(0, new TimeSpan(0,0,0));
RetryConfiguration.SuspendExecutionStrategy = true;
res.Execute(() =>
{
using (var trans = _repoFactory.GetTransactableRepository())
{
trans.BeginTransaction();
var entry = trans.GetAll<MyTable>().First();
entry.Alive = true;
trans.Save();
trans.Commit();
}
});
RetryConfiguration.SuspendExecutionStrategy = false;
Я даже пытался вручную вызвать DefaultExecutionStrategy.Execute ().
var des = new System.Data.Entity.Infrastructure.DefaultExecutionStrategy();
des.Execute(() =>
{
using (var trans = _repoFactory.GetTransactableRepository())
{
trans.BeginTransaction();
var entry = trans.GetAll<MyTable>().First();
entry.Alive = true;
trans.Save();
trans.Commit();
}
});
Даже в этой ситуации я получаю исключение о том, что RetryConfiguration не разрешает инициируемые пользователем транзакции.
Для этого я попытался добавить RetryConfiguration.SuspendExecutionStrategy = true / false в функции BeginTransaction (), Commit () и Rollback () нашего класса TransactableRepository. Сам класс является просто оберткой для соединения. Я не удивился, когда это не сработало, учитывая, что в примере Microsoft только когда-либо показывается, что он читается из конструктора RetryConfiguration, но я решил, что это стоит попробовать, так как я не очень знаком с CallContext.