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

Transient Database contexts from separate dependencies fails for parallel queries

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

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

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

问题

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

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

System.InvalidOperationException: A second operation started on this context before a previous operation completed. This is usually caused by different threads using the same instance of DbContext. For more information on how to avoid threading issues with DbContext, see https://go.microsoft.com/fwlink/?linkid=2097913.

链接页面的第一句话是

Entity Framework Core does not support multiple parallel operations being run on the same DbContext instance.

我认为这很容易解决,方法是将我的缓存加载包装到它自己的 class 并将直接查询包装到另一个,然后让这两个都需要它们自己的数据库上下文实例。然后我的服务可以依次注入这些依赖项并并行使用这两个依赖项。

这应该是我拥有的:

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

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

我也启用了MultipleActiveResultSets=True

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

同样,除了 Singelton 的 HandlerService 之外,一切都是瞬态的,因为我希望它在内存中保留缓存的副本,而不必为每个请求加载它。

关于 ef-core 数据库上下文或一般的 DI,我没能理解什么?

我知道问题出在哪里了。在我的例子中,如上所述,有一个单例处理程序。此处理程序有一个(间接)上下文(通过 DI)用于在加载缓存之前完成请求。如果在加载缓存之前将多个并行查询发送到 API,则会发生此错误,因为这些请求中的每一个都使用相同的上下文。在我的测试中,作为启动的一部分,我总是遇到并行请求,因此 singelton 服务试图对多个请求使用相同的数据库上下文。我的解决方案是在 "normal" 依赖项注入之外的这个地方,使用 IServiceScopeFactory 获取用于在加载缓存之前解析请求的依赖项的新实例。 Bohdan 的回答让我得出了这个结论和最终的解决方案。

我不确定它是否符合完整答案的条件,但它太宽泛了,无法发表评论。

.NET core background services which are obviously singletons too I use IServiceScopeFactory创建生命周期有限的服务时。

这是我创建上下文的方法

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

我的猜测是你可以将它注入你的处理程序并像这样使用它。因此,它允许您将上下文保留为作用域而不是瞬态,这是默认设置顺便说一句。

希望对您有所帮助。