Нетерпеливая загрузка, включаемая с использованием пользовательских процедур загрузки

#c# #entity-framework #asp.net-core #lazy-loading #ef-core-2.2

#c# #entity-framework #asp.net-core #отложенная загрузка #ef-core-2.2

Вопрос:

Я создаю соединение с БД следующим образом:

 protected override void OnConfiguring(DbContextOptionsBuilder optionbuilder)
{
    optionbuilder.UseLazyLoadingProxies().UseSqlite(@"Data Source=Data.db");
}
  

И я пытаюсь получить доступ к объекту следующим образом:

 public static User GetProfile(int uid)
{
    using (Db db = new Db())
    {
        return db.Users.Include(x => x.Settings).FirstOrDefault(x => x.UserId == uid);
    }
}
  

Пользовательский объект выглядит следующим образом:

 public class User
{
    [Key]
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public int UserId { get; set; }

    public string Name { get; set; }
    public DateTime? LastUsed{ get; set; }

    public virtual Setting Settings { get; set; }
}
  

но при доступе Users.Settings он выдает следующую ошибку:

«Ошибка, сгенерированная для предупреждения»Microsoft.EntityFrameworkCore.Инфраструктура.LazyLoadOnDisposedContextWarning: Была предпринята попытка отложенной загрузки навигационного свойства «Настройки» для объекта типа «UserProxy» после удаления связанного DbContext.’. Это исключение может быть подавлено или зарегистрировано путем передачи идентификатора события ‘CoreEventId.LazyLoadOnDisposedContextWarning’ методу ‘ConfigureWarnings’ в ‘DbContext.При настройке’ или ‘AddDbContext’.’

Я понимаю, что это значит, но это противоречит моему пониманию включений и того, как это вызывает нетерпеливую загрузку.

Я понимаю, что при использовании include и явном доступе к объекту путем вызова FirstOrDefault eager load связанные объекты должны быть заполнены немедленно без необходимости сохранения открытого подключения к БД; но, по-видимому, это не так.

Каков был бы правильный способ сделать это, не требуя, чтобы база данных оставалась открытой?

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

1. db.Users.FirstOrDefault(x => x.UserId == uid); Работает ли так, как ожидалось?

2. Да, он отлично загружает все напрямую связанные свойства, только когда я пытаюсь получить доступ .Settings после включения, генерируется исключение.

3. Хорошо! db.Users.Include(x => x.Settings).FirstOrDefault(x => x.UserId == uid); Работает ли, как ожидалось, при UseLazyLoadingProxies() удалении?

4. Ага! Быстрая загрузка отлично работает без объявления UseLazyLoadingProxies() .

5. Похоже, это ошибка в EF Core, вы можете опубликовать проблему здесь: github.com/aspnet/EntityFrameworkCore/issues

Ответ №1:

Auther V, разработчик, работающий над EFC, подтвердил, что это ошибка.

https://github.com/aspnet/EntityFrameworkCore/issues/15170

Документация об этом изменении

Это исправлено в EF Core 3.0.0 RC4, но на момент написания этой статьи недоступно в открытом доступе. Я лично не стал бы предлагать использовать RC4, поскольку он все еще находится в разработке и не очень подходит для общего назначения или производственного использования.

На данный момент вы можете подавить ошибку следующим образом:

 protected override void OnConfiguring(DbContextOptionsBuilder optionbuilder)
{
    optionbuilder.UseSqlite(@"Data Source=Data.db").UseLazyLoadingProxies();
    optionbuilder.ConfigureWarnings(w => w.Ignore(CoreEventId.LazyLoadOnDisposedContextWarning));
}
  

optionbuilder.ConfigureWarnings(w => w.Ignore(CoreEventId.LazyLoadOnDisposedContextWarning)); Строка — это то, что вам нужно.

Но, пожалуйста, имейте в виду, что любое неправильное использование отложенной загрузки также будет проигнорировано, предоставляя варианты с нулевым значением при попытке перемещения объекта для закрытых экземпляров DbContext.