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.