作者:最棒的寒冬腊月_531 | 来源:互联网 | 2023-02-06 11:31
我在一个运行带有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;
错误是:
Microsoft.EntityFrameworkCore.Query.RelationalQueryCompilationContextFactory:错误:迭代查询结果时数据库中发生异常.System.ObjectDisposedException:已关闭安全句柄
Microsoft.EntityFrameworkCore.Query.RelationalQueryCompilationContextFactory:错误:迭代查询结果时数据库中发生异常.System.InvalidOperationException:只能在连接打开时调用ExecuteReader.
对我来说,这两个错误都表明了一些事情正在发生DbContext
,比如过早处置(尽管不是DbContext
自己).该DbContext
被注入在使用DOTNET核心的"通常方式"的管道控制器的构造,配置如下所示(从我的Startup.cs
ConfigureServices
方法体):
services.AddDbContext(optiOns=> options.UseSqlite(connectionString));
如果我将上面的错误产生代码改为:
var r1 = await _dbContext.Awesome.FirstOrDefaultAsync(a => [...]);
var r2 = await _dbContext.Bazinga.FirstOrDefaultAsync(b => [...]);
...我没有看到提到的错误,因此得出的结论是,在我的同一个实例上同时运行多个任务DbContext
(如上所述注入)是造成问题的原因.显然,这是一个意外的.
问题:
我得出了正确的结论,还是还有其他事情发生?
你能找出偶然发生错误的原因吗?
你知道在仍然运行并发任务的同时避免这个问题的任何简单方法DbContext
吗?
Igor..
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
1> Igor..:
不幸的是你做不到.
来自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),该文档指出不支持并行查询.