在Entity Framework 6中使用数据库重试用户事务(连接弹性)

时间:2018-11-07 15:24:23

标签: c# transactions entity-framework-6 postgresql-9.4 devart

我正在尝试对我已经开始工作的数据库连接进行重试,但是它也破坏了我拥有的用户发起的事务。  具体来说,我看到如下错误:

  

已配置的执行策略“ RetryExecutionStrategy”不支持用户启动的事务。有关其他信息,请参见http://go.microsoft.com/fwlink/?LinkId=309381

我非常想实现第一种解决方法from 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添加到我们的TransactableRepository类的BeginTransaction(),Commit()和Rollback()函数中。类本身只是连接的包装器。鉴于微软的示例仅显示了它是从RetryConfiguration的构造函数读取的,因此当它不起作用时,我并不感到惊讶,但是我认为值得尝试一下,因为我对CallContext并不十分熟悉。

0 个答案:

没有答案