Entity Framework Core service default lifetime
在ASP.NET Core应用程序中,我可以像这样通过DI注册DbContext
1 | services.AddDbContext<Models.ShellDbContext>(options => options.UseNpgsql(connection)); |
而知道它的生命周期是什么呢?
从这里https://github.com/aspnet/EntityFramework/blob/f33b76c0a070d08a191d67c09650f52c26e34052/src/Microsoft.EntityFrameworkCore/EntityFrameworkServiceCollectionExtensions.cs#L140看起来它被配置为Scoped意味着在每个请求上创建DbContext实例。
所以问题的第一部分是:
这是真的,如果是的话,它的成本是多少?
第二部分是:
如果我创建一个消耗DbContext并且打算由控制器使用的服务,并且将有一个API来管理DB中的某些实体,那么它是否应该注册为Scoped?
是的,
实例化
但是,在Web应用程序中,使用
如果您在另一侧使用瞬态生命周期,则将失去"事务"功能。使用作用域时,
如果您需要更细粒度的控制,则必须使用工作单元模式(
对于你的第二个问题:
如果您创建服务,则其生命周期必须等于范围或更短的范围(读取:Scoped或瞬态)。
如果您明确需要更长的服务生命周期,则应在服务中注入
你可以用类似的东西来完成这个
1 2 | services.AddTransient<Func<AppDbContext>>( (provider) => new Func<MyDbContext>( () => new AppDbContext())); services.AddSingleton<IMySingletonService, MySingletonService>(); |
您的服务可能如下所示:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | 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(); } } |
注意:在EF Core 2中,现在有一个新方法
If this method is used, at the time a DbContext instance is requested
by a controller we will first check if there is an instance available
in the pool. Once the request processing finalizes, any state on the
instance is reset and the instance is itself returned to the pool.+This is conceptually similar to how connection pooling operates in
ADO.NET providers and has the advantage of saving some of the cost of
initialization of DbContext instance.
https://docs.microsoft.com/en-us/ef/core/what-is-new/ef-core-2.0#high-performance
不可否认,这就是我所学到的。它来自懒惰的KISS虔诚。我避免了其他的复杂问题,并解决了我的早期EF Core DbContext配置问题,没有关注池,范围等。我只是把一个POC放在一起,不关心异步返回值,从Controller链接到存储库等等所有基本上都返回"无效",即字面上的单一"任务"。这导致我的DbContext成员在较低的例程中进行迭代,以便莫名其妙地处理底层的DbContext。我所要做的就是让每个异步方法返回一个