Entity Framework Dotnet Core 控制台应用程序中的核心 DbContext 生命周期
Entity Framework Core DbContext lifecycle in Dotnet Core console app
我有 .net 核心 web api 项目正在使用 Entity Framework Core 到按预期工作的数据库中的 add/edit/delete 记录。
它配置了具有数据访问和服务层的依赖注入,Web api 控制器通过注入的服务层进行交互。
解决方案的这一部分工作得非常好。
不过,我还有一个单独的 .net 核心控制台应用程序,它共享相同的服务层,并且包含一个很长的 运行 任务,该任务会定期轮询相同的数据,但是如果通过以下方式对数据进行了更改网站这不会反映在控制台应用程序每次迭代中检索到的数据中。根据我的研究,我了解到这是由于数据在 DbContext 之外被更改所致。
我对 EF 还是很陌生,所以我想拓宽我的理解。 Web api 每个 Web 请求都使用一个新的数据库上下文,这就是为什么我没有 运行 遇到与控制台应用程序相同的问题,并且在 Web 应用程序方面有很多文章和讨论,但是在控制台应用程序的上下文中不是那么多。
我相信根据我的 'stale' 数据,我在 DbContext 生命周期方面做的不是很正确,而且我坚持一个上下文的时间比理想的要长。
围绕 'using' 语句包装操作 我认为可以在 DI 场景之外执行我需要的操作,但我想了解如何在使用 DI 时实现等效?通过在需要的地方使用“.AsNoTracking”,我设法在一定程度上解决了这个问题,但想知道是否有更好的方法?
此外,在多个系统可能访问相同数据库记录的情况下使用 EF Core 的任何 pointers/documentation 都将非常有帮助。
非常感谢。
更好的解决方案可能是分离您的项目,您将拥有两个不同的上下文,一个为 Web 应用程序创建,另一个为控制台部分创建。
问题是生命周期,虽然瞬态和单例对于几乎所有应用程序都是自然的,但问题来自 Scoped 类型,因为它需要一些东西来限制它们的生命周期,我知道你有两个选择:
一种是将 EF 上下文添加为瞬态,但请注意,由于附加对象将无法拥有相同的上下文,每个服务 class 将成为一个工作单元上下文不能在其他调用中共享
另一种是将上下文保留为作用域,并借助IScopedProvider
接口在您需要的任何地方定义生命周期,这样您就可以创建自己的作用域,这样您可以限制上下文缓存的共享方式(该上下文中的所有内容都将共享相同的上下文,利用附加对象的缓存和管理。它看起来像这样:
public class 栏()
{
public 栏(IServiceScopeFactory scopeFactory)
{
使用(变量范围= scopeFactory.CreateScope())
{
// 使用范围请求服务,他们会
// 共享相同的作用域
scope.ServiceProvider.GetServices<>();
}
}
}
为了清楚起见,我喜欢使用 scopeFactory 来请求一个可以完成所有工作的服务,这样这个服务就可以注入上下文和其他服务,每个人都将共享相同的上下文,就好像它在网络应用程序中是相同的请求。
我喜欢这样使用:
public class MainClassInConsoleNoContext()
{
private readonly IServiceScopeFactory _scopeFactory;
public MainClassInConsoleNoContext(IServiceScopeFactory scopeFactory)
{
_scopeFactory = scopeFactory;
}
public void MyMainAction() {
using(var scope = scopeFactory.CreateScope())
{
scope.ServiceProvider.GetService<MyServiceWithContextAndScope>().MyScopedAction();
}
}
}
public class MyServiceWithContextAndScope()
{
private readonly CoreContext _context;
public MainClassInConsoleNoContext(CoreContext context, OtherService other)
{
...
}
public void MyScopedAction() {
// Here I can use other service, if they both use CoreContext,
// will be the same in all services, since they share the same
// scope
}
}
我有 .net 核心 web api 项目正在使用 Entity Framework Core 到按预期工作的数据库中的 add/edit/delete 记录。
它配置了具有数据访问和服务层的依赖注入,Web api 控制器通过注入的服务层进行交互。
解决方案的这一部分工作得非常好。
不过,我还有一个单独的 .net 核心控制台应用程序,它共享相同的服务层,并且包含一个很长的 运行 任务,该任务会定期轮询相同的数据,但是如果通过以下方式对数据进行了更改网站这不会反映在控制台应用程序每次迭代中检索到的数据中。根据我的研究,我了解到这是由于数据在 DbContext 之外被更改所致。
我对 EF 还是很陌生,所以我想拓宽我的理解。 Web api 每个 Web 请求都使用一个新的数据库上下文,这就是为什么我没有 运行 遇到与控制台应用程序相同的问题,并且在 Web 应用程序方面有很多文章和讨论,但是在控制台应用程序的上下文中不是那么多。
我相信根据我的 'stale' 数据,我在 DbContext 生命周期方面做的不是很正确,而且我坚持一个上下文的时间比理想的要长。
围绕 'using' 语句包装操作 我认为可以在 DI 场景之外执行我需要的操作,但我想了解如何在使用 DI 时实现等效?通过在需要的地方使用“.AsNoTracking”,我设法在一定程度上解决了这个问题,但想知道是否有更好的方法?
此外,在多个系统可能访问相同数据库记录的情况下使用 EF Core 的任何 pointers/documentation 都将非常有帮助。
非常感谢。
更好的解决方案可能是分离您的项目,您将拥有两个不同的上下文,一个为 Web 应用程序创建,另一个为控制台部分创建。
问题是生命周期,虽然瞬态和单例对于几乎所有应用程序都是自然的,但问题来自 Scoped 类型,因为它需要一些东西来限制它们的生命周期,我知道你有两个选择:
一种是将 EF 上下文添加为瞬态,但请注意,由于附加对象将无法拥有相同的上下文,每个服务 class 将成为一个工作单元上下文不能在其他调用中共享
另一种是将上下文保留为作用域,并借助
IScopedProvider
接口在您需要的任何地方定义生命周期,这样您就可以创建自己的作用域,这样您可以限制上下文缓存的共享方式(该上下文中的所有内容都将共享相同的上下文,利用附加对象的缓存和管理。它看起来像这样:public class 栏() { public 栏(IServiceScopeFactory scopeFactory) { 使用(变量范围= scopeFactory.CreateScope()) {
// 使用范围请求服务,他们会 // 共享相同的作用域 scope.ServiceProvider.GetServices<>();
} } }
为了清楚起见,我喜欢使用 scopeFactory 来请求一个可以完成所有工作的服务,这样这个服务就可以注入上下文和其他服务,每个人都将共享相同的上下文,就好像它在网络应用程序中是相同的请求。
我喜欢这样使用:
public class MainClassInConsoleNoContext()
{
private readonly IServiceScopeFactory _scopeFactory;
public MainClassInConsoleNoContext(IServiceScopeFactory scopeFactory)
{
_scopeFactory = scopeFactory;
}
public void MyMainAction() {
using(var scope = scopeFactory.CreateScope())
{
scope.ServiceProvider.GetService<MyServiceWithContextAndScope>().MyScopedAction();
}
}
}
public class MyServiceWithContextAndScope()
{
private readonly CoreContext _context;
public MainClassInConsoleNoContext(CoreContext context, OtherService other)
{
...
}
public void MyScopedAction() {
// Here I can use other service, if they both use CoreContext,
// will be the same in all services, since they share the same
// scope
}
}