【问题标题】:Eager loading doesn't work with BackgroundService急切加载不适用于 BackgroundService
【发布时间】:2022-01-09 09:17:12
【问题描述】:

我正在尝试在运行BackgroundService 的控制台应用程序中加载相关实体, 但它不加载相关实体,我已经有这个问题几个小时了,我只是注意到它只发生在BackgroundService,通过在索引页面模型中注入 DbContext 类在 Web 应用程序中尝试了相同的DbContext ,没有问题。

这是来自控制台应用程序的代码:

后台服务:

public class MyService : BackgroundService
{
    private readonly MyDbContext _context;

    public MyService(MyDbContext context)
    {
        _context = context;
    }

   protected override async Task ExecuteAsync(CancellationToken stoppingToken)
    { 
                     //Jobs always empty!
        var theBatch = _context.Batches.Include(x => x.Jobs).FirstOrDefault();
     } 
}

程序文件:

class Program
{
    static async Task Main(string[] args)
    {
        using IHost host = CreateHostBuilder(args).Build();
        await host.RunAsync();
    }

    static IHostBuilder CreateHostBuilder(string[] args) => Host.CreateDefaultBuilder(args)
       .ConfigureServices((context, services) =>
       {
           services.AddLogging()
         .AddDbContext<MyDbContext>(options => options
         .UseSqlServer(context.Configuration.GetConnectionString("MyConnection")))

         .AddHostedService<MyService>()
         .BuildServiceProvider();
       });
}

我正在使用 .NET 5 和 EF Core 5.0.12

【问题讨论】:

  • 出于好奇。为什么要构建服务提供商?您是否也尝试过在承包商之外的任何其他地方访问上下文,例如在Execute 中,并且只使用构造函数进行分配?
  • 不是我需要的东西,未经我通知就复制了!
  • 我不明白你的建议,我已经这样做了:我在构造函数中分配了上下文,并在Execute方法中访问它
  • 但是您的示例显示在构造函数中使用包含。你是说即使你在execute中访问Batches也是空的?
  • 啊,我明白了。我将编辑器中的代码复制到了错误的地方!

标签: .net-core entity-framework-core eager-loading background-service asp.net-core-hosted-services


【解决方案1】:

你所拥有的应该是书面的。因此,请仔细检查您的配置。正如@Nkosi 指出的那样,您应该使用较短的范围,但是在 ExecuteAsync 中放置一个范围是不够的,因为它返回的 Task 与 BackgroundService 实例具有相同的生命周期。

无论如何,这是一个在 .NET 6 中运行良好的完整重现。

using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;

class Program
{
    static async Task Main(string[] args)
    {
        
        using IHost host = CreateHostBuilder(args).Build();
        await host.RunAsync();
    }

    static IHostBuilder CreateHostBuilder(string[] args) => Host.CreateDefaultBuilder(args)
       .ConfigureServices((context, services) =>
       {
           services.AddLogging()
                    .AddDbContext<MyDbContext>(options => options
                    .UseSqlServer(context.Configuration.GetConnectionString("MyConnection")))
                    .AddHostedService<MyService>()
                    .BuildServiceProvider();
       });
}

public class MyDbContext : DbContext
{
    public MyDbContext(DbContextOptions<MyDbContext> options) : base(options)
    { }
#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable.
    public DbSet<Batch> Batches { get; set; }

    public DbSet<Job> Jobs{ get; set; }
#pragma warning restore CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable.
}

public class Job
{
    public int Id { get; set; }
}

public class Batch
{
    public int Id { get; set; }

    public virtual ICollection<Job> Jobs { get; set; } = new HashSet<Job>();
}

public class MyService : BackgroundService
{
    private readonly MyDbContext _context;

    public MyService(MyDbContext context)
    {
        _context = context;
        context.Database.EnsureDeleted();
        context.Database.EnsureCreated();

        var batch = new Batch();
        batch.Jobs.Add(new Job() );

        context.Batches.Add(batch);
        context.SaveChanges();
        context.ChangeTracker.Clear();
    }



    protected override async Task ExecuteAsync(CancellationToken stoppingToken)
    {
        var theBatch = await _context.Batches.Include(x => x.Jobs).FirstOrDefaultAsync();

        Console.WriteLine(theBatch.Jobs.Count);
    }
}

【讨论】:

    【解决方案2】:

    好的,我在写这篇文章的同时,我真的很生气在这个问题上花费的时间和精力,我不知道该怪谁,微软还是在 .NET 核心项目中安装 EF 6 的人。微软很难找出问题的根源。

    我使用 Include 来自 System.Data.Entity 命名空间而不是 Microsoft.EntityFrameworkCore

    纯属巧合,我无缘无故使用了FirstOrDefaultAsync,得到了这个奇怪的异常:

    '源 IQueryable 的提供者没有实现 IDbAsyncQueryProvider。只有提供者实现 IDbAsyncQueryProvider 可用于 Entity Framework 异步 操作。

    当我查看它时,我发现我为FirstOrDefaultAsync 使用了错误的命名空间(System.Data.Entity 而不是Microsoft.EntityFrameworkCore) 当我更改命名空间时,一切正常!

    【讨论】:

      猜你喜欢
      • 2021-10-08
      • 2018-01-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-01-26
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多