我应该如何在MVC Core中管理DbContext生存期? [英] How should I manage DbContext Lifetime in MVC Core?

查看:103
本文介绍了我应该如何在MVC Core中管理DbContext生存期?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

文档


实体框架上下文使用 Scoped c $ c>寿命。如果您
使用上面显示的帮助程序方法,这将自动执行。使用Entity Framework的
的存储库应使用相同的生存期。

Entity Framework contexts should be added to the services container using the Scoped lifetime. This is taken care of automatically if you use the helper methods as shown above. Repositories that will make use of Entity Framework should use the same lifetime.

我一直认为,我应该创建一个我必须处理的每个工作单元的新 Context 。这让我想想,如果我有 ServiceA ServiceB ,它们在 DbContext ,他们应该获得 DbContext 的其他实例。

I always thought, that I should create a new Context for every single unit of work I have to process. This let me think, if I have a ServiceA and ServiceB, which are applying different actions on the DbContext that they should get a different Instance of DbContext.

a href = https://docs.microsoft.com/zh-cn/aspnet/core/fundamentals/dependency-injection rel = noreferrer>文档内容如下:

The documentation reads as following:



  • 瞬态对象总是不同的;为每个控制器和每个服务提供一个新实例。

  • Transient objects are always different; a new instance is provided to every controller and every service.

范围对象在一个内部请求,但在不同请求中有所不同

Scoped objects are the same within a request, but different across different request

回到 ServiceA ServiceB ,在我看来, Transient 更合适。

Going back to ServiceA and ServiceB, it sounds to me, Transient is more suitable.

我已经研究过,Context应该只为每个 HttpRequest 保存一次,但是我真的不明白这是如何工作的。

I have researched, that the Context should only saved once per HttpRequest, but I really do not understand how this does work.

特别是如果我们看一下一项服务:

Especially if we take a look at one Service:

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

Here we need to Save the context in order to get the ID of an Entity which is related to another one we just have created.

同时,另一项服务可以更新相同的上下文。根据我的阅读, DbContext 不是线程安全的。

At the same time another service could update the same context. From what I have read, DbContext is not thread safe.

我应该使用 Transient 在这种情况下?为什么文档提示我应该使用 Scoped

Should I use Transient in this case? Why does the documentation suggest, I should use Scoped?

我想念一些吗?

推荐答案

正如其他人已经解释过的那样,您应该对数据库上下文,以确保将其正确重用。对于并发性,请记住您也可以异步查询数据库,因此您可能不需要实际的线程。

As others already explained, you should use a scoped dependency for database contexts to make sure it will be properly reused. For concurrency, remember that you can query the database asynchronously too, so you might not need actual threads.

如果您需要 线程,即后台工作人员,那么这些工作人员的生存期可能会与请求不同。这样,这些线程应该使用从请求范围中检索到的依赖项。当请求结束并且其依赖项范围关闭时,可处理的依赖项将被正确处理。对于其他线程,这将意味着尽管它们仍然需要它们,但它们的依赖关系可能最终会被释放:不好的主意。

If you do need threads, i.e. background workers, then it’s likely that those will have a different lifetime than the request. As such, those threads should not use dependencies retrieved from the request scope. When the request ends and its dependency scope is being closed, disposable dependencies will be properly disposed. For other threads, this would mean that their dependencies might end up getting disposed although they still need them: Bad idea.

相反,您应该为您创建的每个线程。您可以通过注入 IServiceScopeFactory 并使用 CreateScope 。然后,生成的对象将包含一个服务提供程序,您可以从中检索依赖关系。由于这是一个单独的作用域,因此将在该作用域的生命周期内重新创建作用域依赖性,例如数据库上下文。

Instead, you should explicitly open a new dependency scope for every thread you create. You can do that by injecting the IServiceScopeFactory and creating a scope using CreateScope. The resulting object will then contain a service provider which you can retrieve your dependencies from. Since this is a seperate scope, scoped dependencies like database contexts will be recreated for the lifetime of this scope.

为了避免进入服务定位器模式,您应该考虑让您的线程执行一项集中所有必要依赖项的中央服务。然后线程可以执行以下操作:

In order to avoid getting into the service locator pattern, you should consider having one central service your thread executes that brings together all the necessary dependencies. The thread could then do this:

using (var scope = _scopeFactory.CreateScope())
{
    var service = scope.ServiceProvider.GetService<BackgroundThreadService>();
    service.Run();
}

BackgroundThreadService 和然后,其所有依赖项都可以遵循接收依赖项的通用依赖项注入方式。

The BackgroundThreadService and all its dependency can then follow the common dependency injection way of receiving dependencies.

这篇关于我应该如何在MVC Core中管理DbContext生存期?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆