#.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
), когда я изменил пространство имен, все работало!