Bezdepbonusu7Программирование: статьи и ответы

Вопрос

Entity Framework: проблема со свойствами навигации

Автор вопроса: aschermanОтветов: 4

Я работаю с кодом Entity Framework в первую очередь, и у меня есть класс Course, который имеет свойство навигации Students:

public virtual Collection<Student> Students { get; set;}

Это работает нормально, но когда я обращаюсь к этому свойству навигации, все данные извлекаются из базы данных:

var allStudents = course.Students; // Here it retrieves the data
var activeStudents = allStudents.Where(n => n.Active); // Here it filter the data on memory
var listOfActiveStudents = activeStudents.ToList(); // It already has the data on memory.

Как вы понимаете, мне нужно, чтобы запрос выполнялся, когда я делаю .ToList(), потому что я не хочу выводить все Students из базы данных, а только активные.

Вы знаете, что я делаю неправильно?

entity-frameworkdbcontextef-code-first

Ответы

Ответ 1 · рейтинг 3 · Colin

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

public GetCourseWithActiveStudentsLoaded(int courseid)
{
   var course= context.Courses.Find(courseid);

   context.Entry(course)
          .Collection(c => c.Students)
          .Query()
          .Where(s => s.Active)
          .Load();

   return user
}

Является ли флаг "Активно" индикатором того, что вы пытаетесь реализовать обратимое удаление? Если это так, здесь есть решение: Soft Delete в Entity Framework

Вы можете проголосовать за отфильтрованные включения здесь: Разрешить фильтрацию для метода расширения Include

Другой способ сделать это - наследование. У вас может быть свойство ActiveStudent, наследуемое от Student, и свойство навигации ActiveStudents, а также свойство навигации AllStudents в классе Course.

public virtual Collection<Student> AllStudents { get; set;}
public virtual Collection<ActiveStudent> ActiveStudents { get; set;}

Ссылка:

Применение фильтров при явной загрузке связанных объектов:

Ответ 2 · рейтинг 3 · Travis J

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

//user is an instance of the class User referenced by DbSet<User>
//when you lazy load a navigation property in that set, it loads the data
ICollection<Student> allStudents = user.Students;

//At this point, all of the data was lazy loaded
//But the Where creates an IEnumerable of the in memory set
IEnumerable<Student> activeStudents = allStudents.Where(n => n.Active);

//At this point, the IEnumerable is iterated, and a List is returned
List<Student> listOfActiveStudents = activeStudents.ToList();

Ответ 3 · рейтинг 3 · Moho

используйте dbContext.Entry( user ).Collection( u => u.Students ).Query(), чтобы получить IQueryable<Student> для свойства навигации коллекции студентов, после чего вы можете добавить свой фильтр и перечислить, когда будете готовы к данным

Ответ 4 · рейтинг 1 · Dave Cousineau

Один из способов обхода этого - перевернуть ваш запрос, хотя это означает отказ от использования свойств навигации в целом. (Фактическая реализация зависит от вашей модели.)

var allStudents =
   context
   .Students
   .Where(s => s.CourseID == course.ID) // depends on your model
   .Where(s => s.Active)
   .ToList();

Я предпочитаю это использованию метода Entry, так как я использую общий интерфейс со своими моделями и не хочу раскрывать типы EF6.

Другой способ избежать раскрытия типов EF6 - написать такой метод:

public IQueryable<TChild> Nav<TParent, TChild>(
   TParent pParent,
   Expression<Func<TParent, ICollection<TChild>>> pNavigationExpression
) where TParent : class
where TChild : class =>
   Entry(pParent)
   .Collection(pNavigationExpression)
   .Query();

Использовал что-то вроде этого:

var allStudents =
   context
   .Nav(course, c => c.Students)
   .Where(s => s.Active)
   .ToList()

Перевод вопроса и ответов сообщества Stack Overflow, лицензия CC BY-SA. Оригинал на Stack Overflow.

Похожие материалы