Entity Framework Ленивая загрузка непредвиденного населения свойства на извлеченных данных - PullRequest
0 голосов
/ 21 сентября 2018

См. Следующий упрощенный пример:

Студенческий класс:

public class Student
{
    public int StudentId { get; set; }
    public string StudentName { get; set; }

    public Grade Grade { get; set; }
}

Класс:

public class Grade
{
    public int GradeId { get; set; }
    public string GradeName { get; set; }

    public ICollection<Student> Students { get; set; }
}

Класс контекста:

public class SchoolContext : DbContext
{
    public SchoolContext() : base()
    {
        Configuration.LazyLoadingEnabled = true;
    }

    public DbSet<Student> Students { get; set; }
    public DbSet<Grade> Grades { get; set; }
}

Программа:

    static void Main(string[] args)
    {
        using (var ctx = new SchoolContext())
        {
            Grade[] grades = ctx.Grades.ToArray();
            Console.WriteLine(grades[0].Students == null);  // True - As expected
            var students = ctx.Students.ToArray();
            Console.WriteLine(grades[0].Students == null);  // False - ? Did not expect that
        }

        Console.Read();
    }

Происходит следующее:

  1. Ленивая загрузка была включена
  2. Список Grades был сохранен в массив
  3. Как и ожидалось, Students свойство навигации объектов ранга было null
  4. Сделал отдельный запрос, чтобы получить Students
  5. EF каким-то образом заполнил Students свойство навигации массива в памяти.

Это может привести к очень дорогим нагрузкам для клиентов, если их не использовать с осторожностью.Кто-нибудь может объяснить почему и как заполнили свойства навигации в массиве?

1 Ответ

0 голосов
/ 21 сентября 2018

Причина, по которой grades[0].Students загружается после выполнения запроса для получения студентов из вашей базы данных с ctx.Students.ToArray();, заключается в том, что вы DbContext отслеживаете изменения .

Это объясняетсяв Документация Entity Framework :

Поведение отслеживания определяет, будет ли Entity Framework Core хранить информацию об экземпляре объекта в своем трекере изменений.Если объект отслеживается, любые изменения, обнаруженные в объекте, будут сохранены в базе данных во время SaveChanges ().Entity Framework Core также исправит свойства навигации между объектами, полученными из запроса отслеживания, и объектами, которые ранее были загружены в экземпляр DbContext.

Это ядро ​​EFдокументы, но это также относится к EF6 для .NET Framework.

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

ctx.Grades.AsNoTracking().ToArray();

... вы можететакже отключите его по умолчанию (например, внутри конструктора DbContext), так же, как вы делаете это для отложенной загрузки.


Другой способ, которым вы могли бы это сделать, - вручную отсоединить объект от контекста.Затем, если вы когда-нибудь намеревались внести какие-либо изменения и сохранить их в базе данных, вам следует заново присоединить вашу сущность после запроса студентов и перед внесением изменений:

using (var ctx = new SchoolContext())
{
    Grade[] grades = ctx.Grades.ToArray();
    Grade firstGrade = grades[0];
    Console.WriteLine(firstGrade.Students == null);  // True - as expected

    ctx.Grades.Detach(firstGrade); // stop tracking changes for this entity
    var students = ctx.Students.ToArray();
    Console.WriteLine(firstGrade.Students == null);  // True - still null

    // Let's reattach so we can track changes and save to database
    ctx.Grades.Attach(firstGrade);
    firstGrade.GradeName = "Some new value"; // will be persisted, as this is being tracked again
    ctx.SaveChanges();
}

Кроме того, стоит отметить lazy loadразрешено , доступ к grades[0].Students в первый раз должен заставить EF загрузить это свойство навигации, если оно еще не было загружено (что и является его целью), однако, похоже, этого не происходит, потому что ваше свойство навигации не virtual.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...