代码之家  ›  专栏  ›  技术社区  ›  Clinton Pierce

两个嵌套的实体框架上下文,共享一个事务

  •  0
  • Clinton Pierce  · 技术社区  · 6 年前

    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 Database.CurrentTransaction 没有设置器。

    • TransactionScope 一切都结束了。问题:方法 OuterMethod 在里面 上下文,我无法控制调用方。

    我不能尝试的:

    • 脏读/不锁定。 AlmostUnrelatedCode()

    我宁愿不要:

    • AlmostUnrelatedCode . 几乎未更新的代码 处理大量的数据树,这种情况下得到脂肪和不高兴真的很快。它很快就用垃圾污染了它的上下文,我宁愿在我完成后就把它处理掉。
    2 回复  |  直到 6 年前
        1
  •  1
  •   layth morrar    6 年前

    可以通过对多个上下文使用一个连接来防止死锁。

    例子

         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
    
        2
  •  1
  •   Jürgen Röhr    6 年前

    你就不能把在家里做的事分开吗 AlmostUnrelatedCode 这样地:

    void AlmostUnrelatedCode()
    {
       var context = _contextFactory.CreateReadOptimized();
       AlmostUnrelatedCode(context);
       context.Dispose();
    }
    
    void AlmostUnrelatedCode(MyDatabase context)
    {
        // Do many, many things with context...
    }
    

    现在你可以打电话了 AlmostUnrelatedCode(with param) OuterMethod . 也许还有更多的东西需要分开。考虑 奥利德。