根据文档,应该使用Scoped
生命周期将Entity Framework上下文添加到服务容器中。如果按照上面显示的帮助方法,则会自动处理此操作。将使用Entity Framework的存储库应使用相同的生命周期。
我一直以为,我应该为每个要处理的工作单元创建一个新的Context
。这让我想到,如果我有一个ServiceA
和ServiceB
,它们正在对DbContext
应用不同的操作,那么它们应该获得DbContext
的不同实例。
文档如下所述:
Transient
对象始终是不同的;每个控制器和每个服务都提供一个新实例。
Scoped
对象在请求内相同,在不同请求之间不同
回到ServiceA
和ServiceB
,听起来对我来说Transient
更合适。
我已经研究过,Context应该仅在每个HttpRequest
中保存一次,但我真的不明白这是如何工作的。
特别是如果我们看一个服务:
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();
}
这里我们需要保存上下文以便获取与我们刚刚创建的实体相关联的实体的ID。
同时,另一个服务可能会更新相同的上下文。根据我所了解的,DbContext
不是线程安全的。
在这种情况下,我应该使用 Transient
吗?为什么文档建议我应该使用 Scoped
?
我是否遗漏了框架的某些重要部分?
DbContext
注册。瞬态生命周期将在每次被另一个服务请求时创建服务的新实例,这将导致每个请求多个DbContext
。在同一请求内重复使用相同的DbContext
实例没有问题:每个请求绑定到单个线程,因此完全不存在线程安全问题。 - Federico DipumaTask.WhenAll(serviceA.DoSomethingWithContext, ServiceB.DoSomethingElseWithContext)
@FedericoDipuma - Christian GollhardtDbContext
中(类似于services.AddSingleton<Func<DbContext>>(s => new Func<DbContext>(() => new MyDbContext(/*..*/)));
),并使用using
语句自己管理它们的生命周期。 - Federico Dipuma