4

Documentation我應該如何管理MVC Core中的DbContext生命週期?

實體框架上下文應該被添加到使用Scoped終身服務容器 。如果您使用如上所示的幫助程序方法,則會自動執行此操作。使用實體框架 的存儲庫應該使用相同的生命週期。

我一直認爲,我應該爲每一個單位的工作單位創造一個新的環境,我必須處理。這讓我想,如果我有一個ServiceAServiceB,它們在DbContext上應用不同的操作,它們應得到不同的實例DbContext

documentation讀取如下:

  • Transient對象總是不同;爲每個控制器和每個服務提供一個新實例。

  • Scoped對象是請求中的相同,但不同的跨越不同的要求

再回到ServiceAServiceB,它的聲音對我來說,Transient更適合。

我研究過,上下文應該只保存一次HttpRequest,但我真的不明白這是如何工作的。

特別是具有如果我們看一看一個服務:

using (var transaction = dbContext.Database.BeginTransaction()) 
{ 
    //Create some entity 
    var someEntity = new SomeEntity(); 
    dbContext.SomeEntity.Add(someEntity); 

    //Save in order to get the the id of the entity 
    dbContext.SaveChanges(); 

    //Create related entity 
    var relatedEntity = new RelatedEntity 
    { 
     SomeEntityId = someEntity.Id 
    }; 
    dbContext.RelatedEntity.Add(relatedEntity) 
    dbContext.SaveChanges(); 
    transaction.Commit(); 
} 

在這裏我們需要保存的背景下,爲了得到這是關係到我們剛剛創造了一個又一個實體的ID。

同時,另一項服務可能會更新相同的上下文。從我讀到的,DbContext不是線程安全的。

在這種情況下,我應該使用Transient嗎?爲什麼文檔提示,我應該使用Scoped

我錯過框架的一些重要部分嗎?

+0

切勿使用臨時'DbContext'註冊。瞬態生命週期將創建一個服務的新實例**每個**它是另一個服務請求的時間。這將導致每個請求有多個'DbContext's。在同一請求中重複使用相同的'DbContext'實例沒有問題:每個請求都綁定到單個線程,所以根本沒有線程安全問題。 –

+0

但是如果服務因爲某種原因(例如Task.Start)並行處理會發生什麼? @FedericoDipuma –

+0

你的意思是*並行*?你是否明確地產生了一個新的線程,你可以使用相同的'DbContext'? –

回答

5

正如其他人已經解釋過,你應該使用一個作用域數據庫上下文的依賴性,以確保它將被正確地重用。對於併發性,請記住,您也可以異步查詢數據庫,因此您可能不需要實際的線程。

如果你做需要線程,即後臺工作人員,那麼它們可能會有不同於請求的生命週期。因此,那些線程應該使用而不是使用從請求範圍檢索的依賴關係。當請求結束並且其依賴關係範圍被關閉時,一次性依賴關係將被正確處置。對於其他線程,這意味着它們的依賴可能最終被丟棄,雖然他們仍然需要它們:壞主意。

相反,您應該爲每個創建的線程顯式打開一個新的依賴範圍。您可以通過注入IServiceScopeFactory並使用CreateScope創建示波器來實現此目的。然後,生成的對象將包含一個服務提供者,您可以從中檢索依賴關係。由於這是一個獨立的作用域,所以在此作用域的整個生命週期中,將重新創建像數據庫上下文這樣的作用域依賴關係。

爲了避免進入服務定位器模式,您應該考慮讓您的線程執行一個集中服務,將所有必需的依賴關係彙集在一起​​。然後線程可以這樣做:

using (var scope = _scopeFactory.CreateScope()) 
{ 
    var service = scope.ServiceProvider.GetService<BackgroundThreadService>(); 
    service.Run(); 
} 

BackgroundThreadService及其所有的依賴則可以按照接收依賴的共同依賴注入方式。

+0

非常好:)謝謝你的詳細解釋。 –

2

我相信在大多數情況下,當您使用作用域生存期時,您不會遇到併發問題。即使在您發佈的示例中,沒有併發問題,因爲當前請求中的服務將隨後調用。我甚至無法想象當你在一個HTTP請求(範圍)的上下文中並行運行2個或更多的服務(它可能但並不常見)。

Lifetimes它只是一種方式來存儲您的數據(這裏很簡單)。只需看看流行的DI框架中的一些終身管理者,他們所有的工作都非常匹配 - 這只是像實現一次性模式的對象那樣的字典。使用瞬態我相信你的get對象方法將總是返回null,所以DI會在每次請求時創建新的實例。SingleInstance將存儲對象類似靜態併發字典的東西,因此容器將只創建一次實例,然後接收現有的實例。

作用域通常意味着作用域對象用於存儲創建的對象。在asp網絡管道中,它通常意味着與每個請求相同(因爲範圍可以通過管道傳遞)

簡而言之,不要擔心只是使用作用域是安全的,您可以根據請求調用它。

我試着在我的解釋很簡單,你可以隨時看看源代碼找到,因爲比賽的細節,因爲你需要在這裏https://github.com/aspnet/DependencyInjection

相關問題