热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

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

如何解决《避免在同一个DbContext上同时运行多个任务的实体框架错误》经验,为你挑选了1个好方法。

我在一个运行带有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),该文档指出不支持并行查询.
推荐阅读
author-avatar
最棒的寒冬腊月_531
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有