来自独立依赖项的瞬态数据库上下文对于并行查询失败

时间:2019-11-22 13:12:56

标签: .net-core entity-framework-core asp.net-core-3.0 .net-core-3.0 ef-core-3.0

背景(TLDR:我需要并行查询)

我正在构建REST服务,该服务需要能够非常快速地回答查询。 因此,我正在将数据库的很大一部分预加载到内存中,并使用该数据进行应答,而不是针对每个请求进行复杂的数据库查询。这样效果很好,并且API的平均响应时间大大低于要求,并且比直接数据库查询要快得多。

但是我有一个问题。该服务大约需要5分钟才能启动并预加载其所有信息。在此期间,它无法回答查询。

问题

我想更改它,以便在预加载阶段进行数据库查询,直到加载内存缓存为止。

这导致我遇到了问题。我需要对数据库进行多个活动查询。在EF Core中尝试过此操作的任何人都可能看到了此消息。

  

System.InvalidOperationException:在上一个操作完成之前,在此上下文上启动了第二个操作。这通常是由使用相同DbContext实例的不同线程导致的。有关如何避免DbContext线程问题的更多信息,请参见https://go.microsoft.com/fwlink/?linkid=2097913

链接页面上的第一句话是

  

实体框架核心不支持多个并行操作   在同一DbContext实例上运行。

我认为,可以通过将缓存加载包装到自己的类中并将直接查询包装到另一个类中,然后使这两个都需要自己的数据库上下文实例来轻松解决。然后,我的服务可以依次注入这些依赖项并并行使用这两个依赖项。

这应该是我所拥有的: enter image description here

我还设置了数据库上下文,以便所有部分都使用瞬态。

services.AddDbContext<IDataContext, DataContext>(options => 
  options.UseSqlServer(connectionString), ServiceLifetime.Transient, ServiceLifetime.Transient
);

我还启用了MultipleActiveResultSets=True

所有这些都会导致与上面列出的错误完全相同的错误。

同样,除了HandlerService(这是Singelton)之外,其他所有东西都是瞬态的,因为我希望它在内存中保留缓存的副本,而不必为每个请求都加载它。

我对ef-core数据库上下文或DI的一般理解是什么?

我弄清楚了问题所在。在我的情况下,如上所述,有一个单例处理程序。该处理程序具有一个(间接的)上下文(通过DI),用于满足请求,直到加载缓存为止。当在加载缓存之前将多个并行查询发送到API时,就会发生此错误,因为这些请求中的每一个都使用相同的上下文。在我的测试中,作为启动的一部分,我总是遇到并行请求,因此singelton服务试图对多个请求使用相同的数据库上下文。我的解决方案是在“常规”依赖项注入之外的这一步骤中完成,并使用IServiceScopeFactory获取用于在加载缓存之前解析请求的依赖项的新实例。 Bohdans的回答使我得出了这个结论和最终解决方案。

1 个答案:

答案 0 :(得分:1)

我不确定它是否符合完整答案的要求,但是对于评论来说太宽泛了。

在进行.NET core background services显然也是单例的操作时,我使用IServiceScopeFactory创建使用寿命有限的服务。

这是我创建上下文的方式

using (var scope = _scopeFactory.CreateScope())
{
    var context = scope.ServiceProvider.GetRequiredService<DbContext>();
}

我的猜测是,您可以将其注入到您的处理程序中并像这样使用它。因此,通过默认设置btw,您可以将上下文保持在范围内,而不是瞬态。

希望有帮助。