Повторная попытка транзакции пользователя с базой данных в Entity Framework 6 (устойчивость соединения) - PullRequest
0 голосов
/ 07 ноября 2018

Я пытаюсь выполнить повторные попытки для моих соединений с базой данных, которые я заработал, но это также нарушает инициируемые пользователем транзакции, которые у меня есть. В частности, я вижу такие ошибки:

Настроенная стратегия выполнения 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.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...