Эффективным способом является составление запроса по всем сущностям, а затем использование .Select()
для заполнения соответствующих моделей представлений. Вы можете заполнить модели представлений самостоятельно или использовать библиотеку, например Automapper, чтобы помочь с более сложными или более крупными моделями представлений. AutoMapper теперь предлагает метод расширения ProjectTo
, который хорошо работает с EF и IQueryable
.
Так, например, если у вас был поиск, который просматривал список курсов с названием, начинающимся с указанных критериев:
Это предполагает, что вы хотите, чтобы студенты и информация о курсе основывались на названии курса. У студентов есть коллекция курсов, но у курсов нет коллекции студентов.
using (var context = new MyContext())
{
var courseIds = context.Courses
.Where(c => c.CourseName.StartsWith(searchText))
.ToList();
var query = context.Students
.Where(s => s.Courses.Any(c => courseIds.Contains(c.CourseId)));
}
Теперь у нас есть IQueryable, который должен дать нам всех студентов, у которых есть хотя бы 1 соответствующий курс. Я отделил поиск курса, чтобы получить только список совпадающих идентификаторов курса, поскольку с ними будет легче сопоставить, чем встраивать этот критерий в следующие запросы. Они могут быть объединены, но если у вас есть несколько различных критериев, им будет легче следовать, используя их для идентификации идентификаторов для следующих запросов.
Ничего не было запущено для базы данных. Следующим шагом будет то, что мы хотим сгладить результат, чтобы перечислить сведения об ученике, например, только с соответствующими курсами. Если мы искали «Математика», мы хотим вернуть только курс или курсы для каждого ученика, которые соответствуют этому шаблону. Студент может принимать "Math 100" и "Math 200"
using (var context = new MyContext())
{
var courseIds = context.Courses
.Where(c => c.CourseName.StartsWith(searchText))
.ToList();
var query = context.Students
.Where(s => s.Courses.Any(c => courseIds.Contains(c.CourseId)));
var viewModels = query.SelectMany( s => s.Courses.Where(c => courseIds.Contains(c.CourseId))
.Select(c => new ScheduleVM
{
StudentName = s.StudentName,
IndexNumber = s.IndexNumber,
CourseName = c.CourseName
})).ToList()
}
Это может быть сведено к одному запросу Linq, но я держал его отдельно, чтобы его было легче охватить. Первый «запрос» извлекал наших студентов, у которых были совпадающие курсы, но в этот момент список курсов ученика был бы всеми курсами, которые студент посещает. В этом примере мы хотим перечислить только соответствующие курсы. Таким образом, от Студента мы делаем SelectMany
, чтобы получить детали курса, и используем условие Where
, чтобы только извлечь курсы с соответствующими идентификаторами. Оттуда мы делаем. Выбор против этих соответствующих курсов. Поскольку мы все еще в рамках SelectMany
против студента, мы все еще можем получить доступ к «s», который представляет текущего студента. Мы "выбираем" нашу модель представления, предоставляя соответствующие столбцы из Student ("s") и Course ("c"). ToList
в конце - это то, что фактически запускает SQL. EF создаст запрос, который фильтрует данные, а затем возвращает только 3 столбца, которые нам нужны для заполнения модели представления.
Надеюсь, это даст вам некоторые идеи о том, как использовать EF для заполнения данных, которые вы хотите передать в ваше представление. Я бы порекомендовал включить идентификаторы в модель представления, даже если вы их не отображаете, поскольку это будет полезно для извлечения соответствующего студента и / или курса для любых действий, которые вы хотите предпринять на основе этих данных.