Нетерпеливая загрузка не работает с BackgroundService

#.net-core #entity-framework-core #eager-loading #background-service #asp.net-core-hosted-services

#.net-ядро #сущность-структура-ядро #нетерпеливая загрузка #справочная информация-сервис #asp.net-основные-размещенные-сервисы

Вопрос:

Я пытаюсь загрузить связанные сущности в консольное приложение , которое запускает BackgroundService , но оно не загружает связанные сущности , у меня уже несколько часов была эта проблема, и я только что заметил, что это происходит только в BackgroundService , попробовал то же DbContext самое в веб-приложении, введя класс 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 =gt; 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) =gt; Host.CreateDefaultBuilder(args)  .ConfigureServices((context, services) =gt;  {  services.AddLogging()  .AddDbContextlt;MyDbContextgt;(options =gt; options  .UseSqlServer(context.Configuration.GetConnectionString("MyConnection")))   .AddHostedServicelt;MyServicegt;()  .BuildServiceProvider();  }); }  

Я использую .NET 5 и EF Core 5.0.12

Комментарии:

1. Из любопытства. Почему вы создаете поставщика услуг? Также вы пробовали получить доступ к контексту где-либо еще за пределами подрядчика, например, в Execute и просто использовать конструктор для назначения?

2. Не для того, что мне нужно, скопировано без моего уведомления!

3. Я не понимаю вашего предложения, я уже сделал это: я назначил контекст в конструкторе и получил доступ к нему в Execute методе

4. Но в вашем примере показано использование параметра включить в конструкторе. Вы хотите сказать, что даже если вы получаете доступ к пакетам в режиме выполнения, он пуст?

5. Ааа, я понимаю. Я скопировал код из своего редактора в неправильных местах здесь!

Ответ №1:

То, что у вас есть, должно работать так, как написано. Поэтому дважды проверьте свою конфигурацию. Как указывает @Nkosi, вы должны использовать более короткие области, но одной области в вашей ExecuteAsync недостаточно, так как возвращаемая задача имеет тот же срок службы, что и экземпляр 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) =gt; Host.CreateDefaultBuilder(args)  .ConfigureServices((context, services) =gt;  {  services.AddLogging()  .AddDbContextlt;MyDbContextgt;(options =gt; options  .UseSqlServer(context.Configuration.GetConnectionString("MyConnection")))  .AddHostedServicelt;MyServicegt;()  .BuildServiceProvider();  }); }  public class MyDbContext : DbContext {  public MyDbContext(DbContextOptionslt;MyDbContextgt; options) : base(options)  { } #pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable.  public DbSetlt;Batchgt; Batches { get; set; }   public DbSetlt;Jobgt; 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 ICollectionlt;Jobgt; Jobs { get; set; } = new HashSetlt;Jobgt;(); }  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 =gt; x.Jobs).FirstOrDefaultAsync();   Console.WriteLine(theBatch.Jobs.Count);  } }  

Ответ №2:

Хорошо, я пишу это, хотя я действительно зол за часы и усилия, потраченные на эту проблему, я не знаю, кого винить, Microsoft или человека, который установил EF 6 в проекте .NET core. Microsoft затруднила поиск источника проблемы.

Я использовал Include из System.Data.Entity пространства имен не Microsoft.EntityFrameworkCore

Я понял это по простому совпадению, я использовал FirstOrDefaultAsync без особой причины, и получил это странное исключение:

«Поставщик исходного IQueryable не реализует IDbAsyncQueryProvider. Только поставщики, реализующие IDbAsyncQueryProvider, могут использоваться для асинхронных операций Entity Framework.

Когда я посмотрел на него, я обнаружил, что использовал неправильное пространство имен для FirstOrDefaultAsync ( System.Data.Entity вместо Microsoft.EntityFrameworkCore ), когда я изменил пространство имен, все работало!