实体框架在分布式事务之后努力恢复

时间:2017-05-02 19:39:42

标签: oracle entity-framework transactionscope distributed-transactions msdtc

使用oracle的ManagedDataAccess.Client.OracleConnection处理由带有EntityFramework的mssql和Oracle(12c)支持的WebApi项目。我们使用autofac为每个请求注入一个上下文实例,但所有oracle访问都是临时完成的。

我们有某些操作同时依赖于两个数据库,因此我们选择使用TransactionScope对象来管理事务。

在大多数情况下,它运作良好,促进分布式的轻量级交易工作很好。但是在完成分布式事务后我遇到了一个问题。

假设:

public void Test() 
{
    var preItem = new HelpItem
    {
        Field1 = "pre batch";
    };
    _context.Items.Add(preItem);
    _context.SaveChanges(); // This save always works.

    var batchResult = FooService.BatchOperation(true);

    var postItem = new HelpItem
    {
        Field1 = "post batch";
    };
    _context.Items.Add(postItem);
    _context.SaveChanges(); // This will succeed/fail depending on whether FooService caused a distributed transaction.
}

使用BatchOperation方法:

public Result BatchOperation(bool triggerDtc) 
{
    using (var transaction = new new TransactionScope(TransactionScopeOption.Required, new TransactionOptions { IsolationLevel = IsolationLevel.ReadCommitted }))
    {
        if (triggerDtc){
            // Make requests to both databases.
        } else {
            // Make request to one database.
        }

        // Always complete for the sake of the demonstration.
        transaction.Complete();
    }
}

如果遇到分布式交易,然后完成&完全处置的EF似乎无法像交易发挥作用一样恢复并重新开始工作。

错误:

  

分布式事务已完成。要么以新的形式登记此会话   事务或NULL事务。

处理此问题的正确方法是什么?

对于这种特殊情况,您可以简单地围绕第二部分创建另一个事务:

var batchResult = FooService.BatchOperation(true);

using (var transaction = new new TransactionScope(TransactionScopeOption.Required, new TransactionOptions { IsolationLevel = IsolationLevel.ReadCommitted }))
{
    var postItem = new HelpItem
    {
        Field1 = "post batch";
    };
    _context.Items.Add(postItem);
    _context.SaveChanges(); // This save depends on whether FooService caused a distributed transaction.
    transaction.Complete();
}

但是这个问题出现了,因为FooService.BatchOperation方法只是对另一个数据库的查找而被改变,在不知不觉中打破了调用后继续使用上下文的每个方法。使用普通事务,可以自由地在其中使用单个EF上下文而不会出现问题,是否有任何方法可以实现与分布式事务相同的操作?

编辑: 这真让我困惑了。只是在另一个(非分布式)事务管理器中发出请求的行为足以恢复EF功能。

public IHttpActionResult Test() 
{
    var preItem = new HelpItem
    {
        Field1 = "pre batch";
    };
    _context.Items.Add(preItem);
    _context.SaveChanges(); // This save works.

    var batchResult = FooService.BatchOperation(true);

    using (var transaction = new new TransactionScope(TransactionScopeOption.Required, new TransactionOptions { IsolationLevel = IsolationLevel.ReadCommitted }))
    {
        var lookupAnything = _context.Items.ToList();
        transaction.Complete(); // This is optional, because we really don't care and it's disposed either way.
    }

    var postItem = new HelpItem
    {
        Field1 = "post batch";
    };
    _context.Items.Add(postItem);
    _context.SaveChanges(); // Now this always works.
}

显然,我无法随处可见,所以仍然不确定实际解决方案是什么。

0 个答案:

没有答案