2017-05-03 101 views
0

有時(特別是在多個選項卡中打開相同的網頁時),我在使用ASP.NET Core上的實體框架保存更改時收到以下異常之一。目前,我在IIS Express上本地運行(通過Visual Studio 2017調試)。使用實體框架與ASP.NET MVC Core獲取SqlTransaction異常

Microsoft.EntityFrameworkCore.DbContext:Error: An exception occurred in the database while saving changes. 
System.InvalidOperationException: This SqlTransaction has completed; it is no longer usable. 
    at System.Data.SqlClient.SqlTransaction.ZombieCheck() 
    at System.Data.SqlClient.SqlTransaction.Commit() 
    ... 

Microsoft.EntityFrameworkCore.DbContext:Error: An exception occurred in the database while saving changes. 
System.NullReferenceException: Object reference not set to an instance of an object. 
    at System.Data.SqlClient.SqlInternalTransaction.Commit() 
    at System.Data.SqlClient.SqlTransaction.Commit() 
    ... 

System.Data.SqlClient.SqlException: The COMMIT TRANSACTION request has no corresponding BEGIN TRANSACTION. 
    at System.Data.SqlClient.SqlInternalConnection.OnError(SqlException exception, Boolean breakConnection, Action`1 wrapCloseInAction) 
    at System.Data.SqlClient.TdsParser.ThrowExceptionAndWarning(TdsParserStateObject stateObj, Boolean callerHasConnectionLock, Boolean asyncClose) 
    ... 

這些引發異常時下面的代碼的SaveChangesAsync()方法被稱爲:

public async void Remove(int statementId) 
{ 
    Statement statement = _data.Statements.FirstOrDefault(s => s.StatementId == statementId); 
    if (statement != null) 
    { 
     _data.Statements.Remove(statement); 
     await _data.SaveChangesAsync(); 
    } 
} 

_dataApplicationDbContext,其作爲每ASP核心文檔可以在控制器中的依賴注射(在這種情況在自定義中間庫類中),並且每次都重複使用,而不像以前那樣包裝在using中。但是,這些錯誤似乎意味着這是不正常的,因爲它應該...

+0

我以爲我指出了這個問題:我的存儲庫類是通過'IServiceCollection'註冊爲'AddTransient()',而這是不正確的生命週期。它[應該是'AddScoped()'](https://docs.microsoft.com/en-us/aspnet/core/fundamentals/dependency-injection)。無論如何,......(某些?)的例外仍然存在。 –

+0

現在,在使用非異步'SaveChanges()'(和'AddScoped')時,這些問題似乎消失了,但我不知道爲什麼異步影響呢? –

+0

現在我知道這可能與使用異步相關,我發現以下內容:[依賴注入的UserManager在異步調用(ASP.NET CORE)上進行處理](http://stackoverflow.com/q/41325518/590790) –

回答

0

這似乎是實體框架連接被刪除,因此這是ApplicationDbContext的生命期的問題。

確保您的倉​​儲類(在一個依靠ApplicationDbContext內部)is registered in IServiceCollection as AddScoped() and not AddTransient()

實體框架的背景下,應加入到使用Scoped終身服務容器 。

此外,use async Task instead of async void for asynchronous methods which do not return anything

異步方法返回void沒有提供一種簡單的方式來通知,他們已經完成了 調用代碼。

看起來像void導致被調用的對象立即被處理(因此關閉連接),因爲沒有什麼可以等待。