.net core 对于并行查询,来自独立依赖项的临时数据库上下文失败

.net core 对于并行查询,来自独立依赖项的临时数据库上下文失败,.net-core,entity-framework-core,asp.net-core-3.0,.net-core-3.0,ef-core-3.0,.net Core,Entity Framework Core,Asp.net Core 3.0,.net Core 3.0,Ef Core 3.0,背景TLDR:我需要并行查询 我正在构建REST服务,它需要能够非常快速地回答问题。 因此,我将数据库的很大一部分预加载到内存中,并使用这些数据进行应答,而不是对每个请求进行复杂的数据库查询。这非常有效,API的平均响应时间远低于要求,比直接数据库查询快得多 但我有个问题。该服务大约需要5分钟启动并预加载其所有信息。在此期间,它无法回答查询 问题 我想对此进行更改,以便在预加载阶段进行数据库查询,直到加载内存缓存 这就引出了一个问题。我需要对我的数据库进行多个活动查询。任何在EF Core中尝试

背景TLDR:我需要并行查询

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

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

问题

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

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

System.InvalidOperationException:在上一个操作完成之前,在此上下文上启动了第二个操作。这通常是由使用同一DbContext实例的不同线程引起的。有关如何避免DbContext线程问题的更多信息,请参阅

链接页面上的第一句话是

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

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

这应该是我所拥有的:

我还设置了数据库上下文,以便它对所有部分使用transient

services.AddDbContext<IDataContext, DataContext>(options => 
  options.UseSqlServer(connectionString), ServiceLifetime.Transient, ServiceLifetime.Transient
);
我还启用了MultipleActiveResultSets=True

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

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

关于ef核心数据库上下文,或者通常的DI,我没有理解的是什么


我知道问题出在哪里了。在我的例子中,有一个如上所述的单例处理程序。这个处理程序有一个通过DI的间接上下文,用于在加载缓存之前满足请求。当在加载缓存之前向API发送多个并行查询时,由于每个请求都使用相同的上下文,因此会发生此错误。在我的测试中,作为启动的一部分,我总是处理并行请求,因此singelton服务试图对多个请求使用相同的db上下文。我的解决方案是在正常依赖项注入之外的这一步中,使用IServiceScopeFactory获取用于在加载缓存之前解析请求的依赖项的新实例。Bohdans的回答让我得出了这个结论和最终的解决方案。

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

在做这些工作时,我使用的显然也是单例服务来创建生命周期有限的服务

下面是我如何创建上下文的

using (var scope = _scopeFactory.CreateScope())
{
    var context = scope.ServiceProvider.GetRequiredService<DbContext>();
}
我猜你可以把它注射到你的手上,然后像这样使用它。因此,它允许您将上下文保留为作用域,而不是使用默认设置btw的瞬态


希望有帮助。

这很有趣,帮助解决了我的问题。我会用我的问题来更新我的问题,并接受这个解决方案,因为它帮助我解决了问题。