避免在同一个DbContext上同时运行多个任务的实体框架错误

Osk*_*erg 10 c# sqlite dbcontext entity-framework-core .net-core

我在一个运行带有Sqlite的Entity Framework Core的Dotnet Core项目中有一个WebApi控制器.

动作中的此代码会出现错误:

var t1 = _dbContext.Awesome.FirstOrDefaultAsync(a => [...]);
var t2 = _dbContext.Bazinga.FirstOrDefaultAsync(b => [...]);
var r1 = await t1;
var r2 = await t2;
Run Code Online (Sandbox Code Playgroud)

错误是:

  • Microsoft.EntityFrameworkCore.Query.RelationalQueryCompilationContextFactory:错误:迭代查询结果时数据库中发生异常.System.ObjectDisposedException:已关闭安全句柄

  • Microsoft.EntityFrameworkCore.Query.RelationalQueryCompilationContextFactory:错误:迭代查询结果时数据库中发生异常.System.InvalidOperationException:只能在连接打开时调用ExecuteReader.

对我来说,这两个错误都表明了一些事情正在发生DbContext,比如过早处置(尽管不是DbContext自己).该DbContext被注入在使用DOTNET核心的"通常方式"的管道控制器的构造,配置如下所示(从我的Startup.cs ConfigureServices方法体):

services.AddDbContext<ApplicationContext>(options => options.UseSqlite(connectionString));
Run Code Online (Sandbox Code Playgroud)

如果我将上面的错误产生代码改为:

var r1 = await _dbContext.Awesome.FirstOrDefaultAsync(a => [...]);
var r2 = await _dbContext.Bazinga.FirstOrDefaultAsync(b => [...]);
Run Code Online (Sandbox Code Playgroud)

...我没有看到提到的错误,因此得出的结论是,在我的同一个实例上同时运行多个任务DbContext(如上所述注入)是造成问题的原因.显然,这是一个意外的.

问题:

  1. 我得出了正确的结论,还是还有其他事情发生?
  2. 你能找出偶然发生错误的原因吗?
  3. 你知道在仍然运行并发任务的同时避免这个问题的任何简单方法DbContext吗?

Igo*_*gor 15

不幸的是你做不到.

来自EF Core文档

EF Core不支持在同一上下文实例上运行多个并行操作.在开始下一个操作之前,应始终等待操作完成.这通常通过在每个异步操作上使用await关键字来完成.

也来自EF 6文档

线程安全

虽然线程安全性会使异步更有用,但它是一个正交特征.目前还不清楚我们是否可以在最常见的情况下实现对它的支持,因为EF与用户代码组成的图形交互以维持状态,并且没有简单的方法来确保此代码也是线程安全的.

目前,EF将检测开发人员是否尝试同时执行两个异步操作并抛出.


A DbContext在任何时间点都只支持单个开放数据阅读器.如果要执行多个并发数据库查询,则需要多个DbContext实例,每个实例对应一个查询.

至于为什么偶尔会出现错误,那就是竞争条件.仅仅因为你在下一个之后开始执行2个任务(没有等待)并不能保证数据库会同时被命中.有时执行时间恰好排队,有时一个任务可能会在另一个任务启动时完成,因此没有冲突.

如何避免它 - 不要这样做,因为它不受支持.等待每个DbContext调用或使用多个DbContext实例.

通过查询我的意思是任何数据库操作,包括SELECT,UPDATE,DELETE,INSERT,ALTER,STORED PROCEDURE CALL,ETC

  • @Igor您可能还想链接到[EF Core文档](https://docs.microsoft.com/en-us/ef/core/querying/async),该文档指出不支持并行查询. (3认同)