簡體   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