【问题标题】:Avoid Entity Framework Error with Multiple Tasks Running Concurrently on Same DbContext避免在同一 DbContext 上同时运行多个任务时出现实体框架错误
【发布时间】:2017-05-16 20:10:35
【问题描述】:

我在使用 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 Core 的管道“常规方式”注入控制器构造函数,配置如下所示(来自我的 Startup.cs ConfigureServices 方法体):

services.AddDbContext<ApplicationContext>(options => options.UseSqlite(connectionString));

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

var r1 = await _dbContext.Awesome.FirstOrDefaultAsync(a => [...]);
var r2 = await _dbContext.Bazinga.FirstOrDefaultAsync(b => [...]);

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

问题:

  1. 我得出了正确的结论,还是发生了其他事情?
  2. 您能否指出错误只是偶尔发生的原因?
  3. 您知道在DbContext 上仍运行并发任务的同时避免该问题的任何简单方法吗?

【问题讨论】:

    标签: c# sqlite .net-core entity-framework-core dbcontext


    【解决方案1】:

    很遗憾,你不能这样做。

    来自EF Core documentation

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

    同样来自EF 6 documentation

    线程安全

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

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


    DbContext 在任何时间点仅支持单个打开的数据读取器。如果您想同时执行多个数据库查询,您将需要多个 DbContext 实例,每个并发查询一个。

    至于为什么偶尔会发生错误,这是一个竞争条件。仅仅因为您一个接一个地启动 2 个任务(没有等待)并不能保证同时命中数据库。有时执行时间恰好对齐,有时一个任务可能会在另一个任务开始时立即完成,因此不会发生冲突。

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

    查询是指任何数据库操作,包括 SELECT、UPDATE、DELETE、INSERT、ALTER、STORED PROCEDURE CALL 等

    【讨论】:

    • 我理解,并且我意识到,当然,我可以通过不这样做来避免它;)我看到您以前曾参与过类似的问题。我之前没有找到它们,因为我没有找到要找的东西。特别感谢文档参考 - 这是一个陷阱,这个。我很好奇为什么我没有收到提到的明确的“不要做并发异步”错误。
    • @OskarLindberg - EF6 内置了一个检查,以尝试检测它是否以这种方式使用,并且将失败并显示正确的错误消息。我猜他们没有在 EF-Core 中构建同样的检查,所以一旦发生冲突它就会失败,但是如果 2 个(或更多任务)碰巧只是安全地相互通过,那么(幸运的是?) 执行调用成功。
    • @Igor 您可能还想链接到声明不支持并行查询的EF Core documentation
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-07-03
    • 2012-08-22
    • 1970-01-01
    • 1970-01-01
    • 2018-12-21
    • 2010-11-18
    • 1970-01-01
    相关资源
    最近更新 更多