2017-05-03 105 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导致被调用的对象立即被处理(因此关闭连接),因为没有什么可以等待。