Учебники

Entity Framework — Ленивая загрузка

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

  • При использовании типов сущностей POCO ленивая загрузка достигается созданием экземпляров производных типов прокси-серверов, а затем переопределением виртуальных свойств для добавления обработчика загрузки.

  • Ленивая загрузка по умолчанию.

  • Если вы оставите конфигурацию по умолчанию и не будете явно указывать Entity Framework в своем запросе, что вы хотите что-то кроме ленивой загрузки, то ленивая загрузка — это то, что вы получите.

  • Например, при использовании класса сущностей Студент соответствующие заявки будут загружены при первом обращении к свойству навигации по заявкам.

  • Свойство навигации должно быть определено как общедоступное, виртуальное. Контекст НЕ будет выполнять отложенную загрузку, если свойство не определено как виртуальное.

При использовании типов сущностей POCO ленивая загрузка достигается созданием экземпляров производных типов прокси-серверов, а затем переопределением виртуальных свойств для добавления обработчика загрузки.

Ленивая загрузка по умолчанию.

Если вы оставите конфигурацию по умолчанию и не будете явно указывать Entity Framework в своем запросе, что вы хотите что-то кроме ленивой загрузки, то ленивая загрузка — это то, что вы получите.

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

Свойство навигации должно быть определено как общедоступное, виртуальное. Контекст НЕ будет выполнять отложенную загрузку, если свойство не определено как виртуальное.

Ниже приведен класс Student, который содержит свойство навигации Enrollments.

public partial class Student {

   public Student() {
      this.Enrollments = new HashSet<Enrollment>();
   }
	
   public int ID { get; set; }
   public string LastName { get; set; }
   public string FirstMidName { get; set; }
   public System.DateTime EnrollmentDate { get; set; }
	
   public virtual ICollection<Enrollment> Enrollments { get; set; }
}

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

class Program {

   static void Main(string[] args) {

      using (var context = new UniContextEntities()) {

         //Loading students only
         IList<Student> students = context.Students.ToList<Student>();

         foreach (var student in students) {

            string name = student.FirstMidName + " " + student.LastName;
            Console.WriteLine("ID: {0}, Name: {1}", student.ID, name);
	
            foreach (var enrollment in student.Enrollments) {
               Console.WriteLine("Enrollment ID: {0}, Course ID: {1}", 
                  enrollment.EnrollmentID, enrollment.CourseID);
            }
         }

         Console.ReadKey();
      }
   }
}	

Когда приведенный выше код скомпилирован и выполнен, вы получите следующий вывод.

ID: 1, Name: Ali Alexander
       Enrollment ID: 1, Course ID: 1050
       Enrollment ID: 2, Course ID: 4022
       Enrollment ID: 3, Course ID: 4041
ID: 2, Name: Meredith Alonso
       Enrollment ID: 4, Course ID: 1045
       Enrollment ID: 5, Course ID: 3141
       Enrollment ID: 6, Course ID: 2021
ID: 3, Name: Arturo Anand
       Enrollment ID: 7, Course ID: 1050
ID: 4, Name: Gytis Barzdukas
       Enrollment ID: 8, Course ID: 1050
       Enrollment ID: 9, Course ID: 4022
ID: 5, Name: Yan Li
       Enrollment ID: 10, Course ID: 4041
ID: 6, Name: Peggy Justice
       Enrollment ID: 11, Course ID: 1045
ID: 7, Name: Laura Norman
       Enrollment ID: 12, Course ID: 3141

Отключить ленивую загрузку

Ленивая загрузка и сериализация не очень хорошо сочетаются, и если вы не будете осторожны, вы можете в конечном итоге запросить всю базу данных только потому, что включена отложенная загрузка. Хорошей практикой является отключение отложенной загрузки перед сериализацией объекта.

Отключение для определенных свойств навигации

Ленивую загрузку коллекции Enrollments можно отключить, сделав свойство Enrollments не виртуальным, как показано в следующем примере.

public partial class Student { 

   public Student() { 
      this.Enrollments = new HashSet<Enrollment>(); 
   }
	
   public int ID { get; set; } 
   public string LastName { get; set; } 
   public string FirstMidName { get; set; } 
   public System.DateTime EnrollmentDate { get; set; }
	
   public ICollection<Enrollment> Enrollments { get; set; } 
}

Выключить все объекты

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

public partial class UniContextEntities : DbContext { 

   public UniContextEntities(): base("name = UniContextEntities") {
      this.Configuration.LazyLoadingEnabled = false;
   }
	
   protected override void OnModelCreating(DbModelBuilder modelBuilder) { 
      throw new UnintentionalCodeFirstException(); 
   } 
}

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

ID: 1, Name: Ali Alexander
ID: 2, Name: Meredith Alons
ID: 3, Name: Arturo Anand
ID: 4, Name: Gytis Barzduka
ID: 5, Name: Yan Li
ID: 6, Name: Peggy Justice
ID: 7, Name: Laura Norman
ID: 8, Name: Nino Olivetto

Мы рекомендуем выполнить вышеприведенный пример пошагово для лучшего понимания.