实体框架核心服务默认生命周期 [英] Entity Framework Core service default lifetime
问题描述
在 ASP.NET Core 应用程序中,我可以像这样通过 DI 注册 DbContext
In ASP.NET Core application I can register DbContext through DI like this
services.AddDbContext<Models.ShellDbContext>(options => options.UseNpgsql(connection));
知道它的生命周期有多长很有趣?
And it is intersting to know what is its lifetime?
From here https://github.com/aspnet/EntityFramework/blob/f33b76c0a070d08a191d67c09650f52c26e34052/src/Microsoft.EntityFrameworkCore/EntityFrameworkServiceCollectionExtensions.cs#L140 it looks like it is configured as Scoped that means DbContext instance is created on every request.
所以问题的第一部分是:是真的吗?如果是,那么它的成本是多少?
So first part of the question is: Is it true and if yes, then how costly it is?
第二部分是:如果我创建了一个使用 DbContext 的服务,并打算由控制器使用,并且将有一个 API 来管理数据库中的某些实体,它是否也应该注册为 Scoped?
And second part is: If I create a service what consumes DbContext, and intended to be consumed by Controllers, and will have an API to manage some entities in DB, should it be registered as Scoped also?
推荐答案
是的,DbContext
的默认生命周期是有范围的.这是这样的.
Yes, the default life time for DbContext
is scoped. This is intended this way.
实例化 DbContext
非常便宜,它确保您不使用许多资源.如果您有一个具有单例生命周期的 DbContext
,那么您读取一次的所有记录都将被 DbContext
跟踪,除非您明确禁用跟踪.这将需要更多的内存使用量,并且会继续增长.
Instantiating DbContext
is pretty cheap and it makes sure that the your do not use to many resources. If you'd have a DbContext
with a singleton lifetime, then all records that you read once will be tracked by the DbContext
, unless you specifically disable tracking. This will require much more memory usage and it will keep growing.
DbContext
跟踪的越多,性能就越低.这就是为什么您经常看到 DbContext
仅在 using(var context = new AppDbContext())
块中使用的原因.
And the more the DbContext
tracks, the lower the performance will be. That's why you often see DbContext
only used within a using(var context = new AppDbContext())
block.
然而,在 web 应用程序中,使用 using
块是不好的,因为生命周期由 framework 并且如果您提前处置它,之后的调用将失败并出现异常.
In web applications however, using the using
block is bad, because the lifetime is managed by the framework and if you dispose it to early the calls after that will fail with an exception.
如果你在另一边使用瞬态生命周期,你将失去交易"功能.有了作用域,DbContext
有一个与请求一样长的事务作用域.
If you use transient lifetime on the other side, you will lose the "transaction" functionality. With scoped, the DbContext
has a transaction scope that's as long as the request.
如果您需要更细粒度的控制,则必须使用工作单元模式(DbContext
已经在使用).
If you need more fine-grained control, you have to use the Unit of Work pattern (which DbContext
already kind of utilize).
对于你的第二个问题:
如果您创建一个服务,它的生命周期必须等于范围之一或更短(阅读:范围或瞬态).
If you create a service, it must have a lifetime that's equal to the one of the scope or shorter (read: Scoped or transient).
如果您明确需要更长的服务生命周期,您应该将 DbContext
工厂服务或工厂方法注入您的服务.
If you explicitly need a longer life-time for a service, you should inject a DbContext
factory service or factory method into your service.
你可以用像
services.AddTransient<Func<AppDbContext>>( (provider) => new Func<MyDbContext>( () => new AppDbContext()));
services.AddSingleton<IMySingletonService, MySingletonService>();
您的服务可能如下所示:
And your service may look like this:
public class MySingletonService : IMySingletonService, IDisposable
{
private readonly AppDbContext context;
public MySingletonService(Func<AppDbContext> contextFactory)
{
if(contextFactory == null)
throw new ArgumentNullException(nameof(contextFactory));
// it creates an transient factory, make sure to dispose it in `Dispose()` method.
// Since it's member of the MySingletonService, it's lifetime
// is effectively bound to it.
context = contextFactory();
}
}
这篇关于实体框架核心服务默认生命周期的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!