繁体   English   中英

两个嵌套的Entity Framework上下文,共享一个事务

[英]Two nested Entity Framework contexts, sharing a transaction

我有看起来像下面的示例的代码。 由于需要通过SP完成一些数据库伪造,并且其中包含一个保存更改,因此涉及到显式事务。 (异常处理,回滚等。省略):

void OuterMethod(MyDatbase context)
{
    using(var dbTrans = context.Database.BeginTransaction())
    {
        // some stuff, the save puts the data where the SP can see it
        Stuff(context);
        context.SaveChanges();

        // now some SP stuff
        context.Database.ExecuteSqlCommand(@"spFoo", params);

        // more stuff
        MoreStuff(context);
        AlmostUnrelatedCode(context);
        context.SaveChanges();

        dbTrans.Commit();
    }
}

现在,方法AlmostUnrelatedCode() -仅与上述过程略相关-在99%的时间中需要一个不错的,快速的,一次性的只读上下文。 我有一家工厂,可以在需要时为我提供合适的服务。 从上面那个块的中间被调用的时间的1%。

MyDatabase localReadOnlyContext;

void AlmostUnrelatedCode(MyDatabase context)
{
    if ( context.Database.CurrentTransaction != null )
    {
        // Must use the context passed or everything deadlocks  :(
        localReadOnlyContext = context;
        disposeContextLater = false;
    }
    else
    {
        // I just want to do this all the time
        localReadOnlyContext = _contextFactory.CreateReadOptimized();
        disposeContextLater = true;
    }

    // Do many, many things with my read-optimized context...

    // The Dispose() on the class will check for disposeContextLater
}

我想做的是摆脱该事务检查,实际上,如果我能帮助的话,根本不需要传递外部上下文。

我试过的

  • 只是忽略外部事务中发生的事情,并一直使用我生成的上下文。 问题:僵局。

  • 尝试将最外层事务放入_contextFactory创建的EF上下文中。 问题:EF上下文构造函数不允许您传递现有事务。 Database.CurrentTransaction也没有设置器。

  • 将整个事务拉出到包裹所有内容的TransactionScope中。 问题:方法OuterMethod 上下文中传递,并且我无法控制调用者。

我无法尝试的是:

  • 脏读/ nolock。 AlmostUnrelatedCode()需要到目前为止已写入的数据。

我宁愿不:

  • 只需在AlmostUnrelatedCode内部使用外部上下文AlmostUnrelatedCode AlmostUnrelatedCode处理大量数据树,并且上下文很快变得发胖和不快乐。 它很快就用废话污染了上下文,我宁愿在完成后就将其丢弃。

您可以通过将一个连接用于多个上下文来防止死锁。

     var efConnectionString = ConfigurationManager.ConnectionStrings["SomeEntities"].ConnectionString;
    // note EntityConnection, not SqlConnection
    using (var conn = new EntityConnection(efConnectionString)) {
        // important to prevent escalation
        await conn.OpenAsync();
        using (var c1 = new SomeEntities(conn, contextOwnsConnection: false)) {
            //Use some stored procedures etc.
            count1 = await c1.SomeEntity1.CountAsync();
        }

        using (var c2 = new SomeEntities(conn, contextOwnsConnection: false)) {
            //Use some stored procedures etc.
            count2 = await c2.SomeEntity21.CountAsync();
        }
    }

在您的情况下,只需从上下文获取连接并重用它

context.Database.Connection

AlmostUnrelatedCode像这样将在AlmostUnrelatedCode完成的事情分开:

void AlmostUnrelatedCode()
{
   var context = _contextFactory.CreateReadOptimized();
   AlmostUnrelatedCode(context);
   context.Dispose();
}

void AlmostUnrelatedCode(MyDatabase context)
{
    // Do many, many things with context...
}

现在,您可以从OuterMethod调用AlmostUnrelatedCode(with param) 也许还有更多的东西需要分离。 考虑S OLID。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM