Entity Framework - ładowanie z opóźnieniem

Ładowanie z opóźnieniem to proces, w którym jednostka lub kolekcja jednostek jest automatycznie ładowana z bazy danych przy pierwszym dostępie do właściwości odwołującej się do jednostki / jednostek. Leniwe ładowanie oznacza opóźnianie wczytywania powiązanych danych, dopóki nie zażądasz tego.

  • W przypadku korzystania z typów jednostek POCO leniwe ładowanie uzyskuje się przez utworzenie wystąpień pochodnych typów proxy, a następnie przesłanianie właściwości wirtualnych w celu dodania zaczepu ładowania.

  • Leniwe ładowanie jest prawie domyślne.

  • Jeśli opuścisz domyślną konfigurację i nie powiesz wyraźnie Entity Framework w zapytaniu, że chcesz coś innego niż ładowanie z opóźnieniem, otrzymasz ładowanie z opóźnieniem.

  • Na przykład podczas korzystania z klasy jednostki Student powiązane rejestracje zostaną załadowane przy pierwszym dostępie do właściwości nawigacji Enrollments.

  • Właściwość nawigacji powinna być zdefiniowana jako publiczna, wirtualna. Kontekst będzieNOT wykonaj ładowanie z opóźnieniem, jeśli właściwość nie jest zdefiniowana jako wirtualna.

Poniżej znajduje się klasa Student, która zawiera właściwość nawigacji 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; }
}

Przyjrzyjmy się prostemu przykładowi, w którym lista studentów jest najpierw ładowana z bazy danych, a następnie wczytuje zapisy konkretnego ucznia, kiedy tego potrzebujesz.

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();
      }
   }
}

Gdy powyższy kod zostanie skompilowany i wykonany, otrzymasz następujące dane wyjściowe.

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

Wyłącz leniwe ładowanie

Leniwe ładowanie i serializacja nie mieszają się dobrze, a jeśli nie jesteś ostrożny, możesz zakończyć wykonywanie zapytań dotyczących całej bazy danych tylko dlatego, że jest włączone ładowanie z opóźnieniem. Dobrą praktyką jest wyłączenie leniwego ładowania przed serializacją jednostki.

Wyłączanie określonych właściwości nawigacji

Leniwe ładowanie kolekcji Enrollments można wyłączyć, ustawiając właściwość Enrollments jako niewirtualną, jak pokazano w poniższym przykładzie.

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; } 
}

Wyłącz dla wszystkich jednostek

Ładowanie z opóźnieniem można wyłączyć dla wszystkich jednostek w kontekście, ustawiając flagę właściwości Configuration na false, jak pokazano w poniższym przykładzie.

public partial class UniContextEntities : DbContext { 

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

Po wyłączeniu leniwego ładowania, po ponownym uruchomieniu powyższego przykładu zobaczysz, że zapisy nie są ładowane i pobierane są tylko dane uczniów.

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

Zalecamy wykonanie powyższego przykładu krok po kroku w celu lepszego zrozumienia.