实体框架上下文应添加到服务容器中 使用
Scoped
生命周期。如果您自动处理 使用如上所示的辅助方法。将使用的存储库 实体框架应使用相同的生命周期。
我一直认为,我应该为我必须处理的每一个工作单元创建一个新的Context
。这让我想一想,如果我有一个ServiceA
和ServiceB
,它们会对DbContext
应用不同的操作,他们应该获得DbContext
的不同实例。
documentation内容如下:
Transient
个对象总是不同的;每个控制器和每个服务都提供一个新实例。
Scoped
个对象在请求中是相同的,但在不同请求中是不同的
回到ServiceA
和ServiceB
,对我来说,Transient
更合适。
我研究过,上下文每{... 1}只能保存一次,但我真的不明白这是如何工作的。
特别是如果我们看一个服务:
HttpRequest
这里我们需要保存上下文,以获取与我们刚刚创建的另一个实体相关的实体的ID。
同时,另一项服务可以更新相同的上下文。根据我的阅读,using (var transaction = dbContext.Database.BeginTransaction())
{
//Create some entity
var someEntity = new SomeEntity();
dbContext.SomeEntity.Add(someEntity);
//Save in order to get the the id of the entity
dbContext.SaveChanges();
//Create related entity
var relatedEntity = new RelatedEntity
{
SomeEntityId = someEntity.Id
};
dbContext.RelatedEntity.Add(relatedEntity)
dbContext.SaveChanges();
transaction.Commit();
}
不是线程安全的。
在这种情况下我应该使用DbContext
吗?为什么文档提示,我应该使用Transient
?
我是否会错过框架的一些重要部分?
答案 0 :(得分:22)
正如其他人已经解释的那样,应该对数据库上下文使用作用域依赖项,以确保它可以正确地重用。对于并发性,请记住您也可以异步查询数据库,因此可能不需要实际的线程。
如果你需要线程,即后台工作者,那么它们的生命周期可能与请求不同。因此,那些线程应不使用从请求范围检索的依赖项。当请求结束并且其依赖范围被关闭时,将适当地处理一次性依赖性。对于其他线程,这意味着他们的依赖关系最终可能会被处理掉,尽管他们仍然需要它们:不好的想法。
相反,您应该为您创建的每个线程显式打开一个新的依赖项范围。您可以通过注入IServiceScopeFactory
并使用CreateScope
创建范围来实现此目的。然后,生成的对象将包含一个服务提供程序,您可以从中检索依赖项。由于这是一个单独的范围,因此将在此范围的生命周期内重新创建范围内的依赖关系,如数据库上下文。
为了避免进入服务定位器模式,您应该考虑让线程执行一个集中服务,将所有必需的依赖项集合在一起。然后线程可以这样做:
using (var scope = _scopeFactory.CreateScope())
{
var service = scope.ServiceProvider.GetService<BackgroundThreadService>();
service.Run();
}
BackgroundThreadService
及其所有依赖关系可以遵循接收依赖关系的公共依赖注入方式。
答案 1 :(得分:2)
我相信在大多数情况下使用作用域生存期时,您不会遇到并发问题。即使在发布的示例中,也没有并发问题,因为随后将调用当前请求中的服务。我甚至无法想象在一个HTTP请求(范围)的上下文中并行运行2个或更多服务(可能但不常见)的情况。
生命周期只是存储数据的一种方式(这里很简单)。只看一下流行的DI框架中的一些终身经理,所有这些工作都非常匹配 - 这只是实现一次性模式的对象的字典。使用Transient我相信你的get对象方法将始终返回null,因此DI将在每次请求时创建新实例。 SingleInstance会将对象存储在静态并发字典之类的内容中,因此容器只会创建一次实例,然后接收现有的实例。
Scoped通常是指范围对象用于存储创建的对象。在asp网络管道中,它通常意味着与每个请求相同(因为范围可以通过管道传递)
要简短 - 不要担心只使用范围它是安全的,你可以根据要求调用它。
我在解释中试图变得非常简单,您可以随时查看源代码,以便在此处找到匹配的详细信息https://github.com/aspnet/DependencyInjection