#c# #entity-framework #entity-framework-6 #lazy-loading
Вопрос:
В EF, пытаясь понять, что такое ленивая загрузка, отметили навигацию по зачислениям как виртуальную.
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: 1, Name: Ali Alexander
ID: 2, Name: Meredith Alons
ID: 3, Name: Arturo Anand
Итак, чего я не понимаю, так это того, почему отключение ленивой загрузки приводит к тому, что не загружаются записи студентов, которые все еще являются собственностью студентов? что происходит?
Комментарии:
1. Взгляните на различные способы загрузки связанных данных . Вам нужно явно загрузить его, если не ленивая загрузка. Будь то «Нетерпеливая загрузка» или «Явная загрузка».
2. Потому что это ссылочное свойство, т. е. свойство, представляющее связь с другой таблицей. Посмотрите документы .
Ответ №1:
Отключение ленивой загрузки не означает, что она будет загружаться с нетерпением, это означает, что она просто не будет загружаться с задержкой, оставляя ссылки #null, если только DbContext их уже не загрузил. Если вы знаете, что вам нужны записи, когда вы загружаете студента, то загружайте их с нетерпением Include
, независимо от того, включена ли отложенная загрузка или нет.
Чтобы обозначить разницу:
С ленивой загрузкой:
// This line executes SQL like "SELECT * FROM dbo.Students"
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);
// This line will execute SQL line "SELECT * FROM dbo.Enrollments WHERE StudentId = {student.StudentId}
foreach (var enrollment in student.Enrollments) {
// ....
}
}
Vs. Нетерпеливая загрузка:
// This line executes SQL like "SELECT * FROM dbo.Students s INNER JOIN dbo.Enrollments e ON e.StudentId = s.StudentId"
IList<Student> students = context.Students.Include(x => x.Enrollments).ToList<Student>();
foreach (var student in students) {
string name = student.FirstMidName " " student.LastName;
Console.WriteLine("ID: {0}, Name: {1}", student.ID, name);
// This line no longer triggers any DB call.
foreach (var enrollment in student.Enrollments) {
// ....
}
}
Разница в производительности может быть весьма существенной. Если бы вы загрузили 100 студентов и их зачисление, ленивая загрузка привела бы к отправке 101 запроса в базу данных и ожиданию. Один для студентов, затем для каждого студента, еще один для зачисленных. Если бы у студента было 4 или 5 ссылок, это могло бы быть 401-501 запросом. При активной загрузке это всегда будет один запрос. Для больших объектов с большим количеством ссылок или большим количеством возвращаемых записей это все равно может легко привести к ошибкам в производительности, которых следует опасаться.