Samouczek: odczytywanie powiązanych danych — ASP.NET MVC za pomocą polecenia EF Core
W poprzednim samouczku ukończono model danych Szkoły. W tym samouczku będziesz odczytywać i wyświetlać powiązane dane — czyli dane ładowane przez program Entity Framework do właściwości nawigacji.
Na poniższych ilustracjach przedstawiono strony, z którymi będziesz pracować.
W tym samouczku zostały wykonane następujące czynności:
- Dowiedz się, jak ładować powiązane dane
- Tworzenie strony Kursy
- Tworzenie strony Instruktorzy
- Dowiedz się więcej o jawnym ładowaniu
Wymagania wstępne
Dowiedz się, jak ładować powiązane dane
Istnieje kilka sposobów, na które oprogramowanie mapowania relacyjnego (ORM), takie jak Entity Framework, może załadować powiązane dane do właściwości nawigacji jednostki:
Chętne ładowanie: gdy jednostka jest odczytywana, powiązane dane są pobierane wraz z nim. Zazwyczaj powoduje to utworzenie pojedynczego zapytania sprzężenia, które pobiera wszystkie potrzebne dane. Możesz określić chętne ładowanie w programie Entity Framework Core przy użyciu
Include
metod iThenInclude
.Niektóre dane można pobrać w osobnych zapytaniach, a program EF "naprawia" właściwości nawigacji. Oznacza to, że program EF automatycznie dodaje oddzielnie pobrane jednostki, w których należą do właściwości nawigacji poprzednio pobranych jednostek. W przypadku zapytania pobierającego powiązane dane można użyć
Load
metody zamiast metody zwracającej listę lub obiekt, na przykładToList
lubSingle
.Ładowanie jawne: gdy jednostka jest najpierw odczytywana, powiązane dane nie są pobierane. Napiszesz kod, który pobiera powiązane dane, jeśli są potrzebne. Podobnie jak w przypadku chętnego ładowania z oddzielnymi zapytaniami, jawne ładowanie powoduje wysłanie wielu zapytań do bazy danych. Różnica polega na tym, że w przypadku jawnego ładowania kod określa właściwości nawigacji do załadowania. W programie Entity Framework Core 1.1 można użyć
Load
metody do jawnego ładowania. Przykład:Ładowanie z opóźnieniem: gdy jednostka jest najpierw odczytywana, powiązane dane nie są pobierane. Jednak przy pierwszej próbie uzyskania dostępu do właściwości nawigacji pobierane są automatycznie dane wymagane dla tej właściwości nawigacji. Zapytanie jest wysyłane do bazy danych za każdym razem, gdy próbujesz pobrać dane z właściwości nawigacji po raz pierwszy. Program Entity Framework Core 1.0 nie obsługuje ładowania leniwego.
Zagadnienia dotyczące wydajności
Jeśli wiesz, że potrzebujesz powiązanych danych dla każdej pobranej jednostki, chętne ładowanie często zapewnia najlepszą wydajność, ponieważ pojedyncze zapytanie wysyłane do bazy danych jest zwykle bardziej wydajne niż oddzielne zapytania dla każdej pobranej jednostki. Załóżmy na przykład, że każdy dział ma dziesięć powiązanych kursów. Chętne ładowanie wszystkich powiązanych danych spowodowałoby tylko jedno zapytanie (sprzężenie) i jedną rundę do bazy danych. Oddzielne zapytanie dotyczące kursów dla każdego działu spowodowałoby jedenaście rund do bazy danych. Dodatkowe rundy do bazy danych są szczególnie szkodliwe dla wydajności, gdy opóźnienie jest wysokie.
Z drugiej strony, w niektórych scenariuszach oddzielne zapytania są bardziej wydajne. Chętne ładowanie wszystkich powiązanych danych w jednym zapytaniu może spowodować wygenerowanie bardzo złożonego sprzężenia, którego program SQL Server nie może wydajnie przetworzyć. Jeśli jednak musisz uzyskać dostęp do właściwości nawigacji jednostki tylko dla podzestawu zestawu przetwarzanych jednostek, oddzielne zapytania mogą działać lepiej, ponieważ chętne ładowanie wszystkiego z góry spowoduje pobranie większej ilości danych niż potrzebujesz. Jeśli wydajność jest krytyczna, najlepiej przetestować wydajność na oba sposoby, aby dokonać najlepszego wyboru.
Tworzenie strony Kursy
Jednostka Course
zawiera właściwość nawigacji zawierającą Department
jednostkę działu, do której przypisano kurs. Aby wyświetlić nazwę przypisanego działu na liście kursów, musisz pobrać Name
właściwość z Department
jednostki, która znajduje się we Course.Department
właściwości nawigacji.
Utwórz kontroler o nazwie CoursesController
dla Course
typu jednostki przy użyciu tych samych opcji dla kontrolera MVC z widokami przy użyciu szkieletu StudentsController
programu Entity Framework, który został wcześniej utworzony dla elementu , jak pokazano na poniższej ilustracji:
Otwórz CoursesController.cs
i sprawdź metodę Index
. Automatyczne tworzenie szkieletów określiło chętne ładowanie właściwości Department
nawigacji przy użyciu Include
metody .
Zastąp metodę Index
następującym kodem, który używa bardziej odpowiedniej nazwy dla IQueryable
obiektu zwracającego jednostki Course (courses
zamiast schoolContext
):
public async Task<IActionResult> Index()
{
var courses = _context.Courses
.Include(c => c.Department)
.AsNoTracking();
return View(await courses.ToListAsync());
}
Otwórz Views/Courses/Index.cshtml
i zastąp kod szablonu następującym kodem. Zmiany są wyróżnione:
@model IEnumerable<ContosoUniversity.Models.Course>
@{
ViewData["Title"] = "Courses";
}
<h2>Courses</h2>
<p>
<a asp-action="Create">Create New</a>
</p>
<table class="table">
<thead>
<tr>
<th>
@Html.DisplayNameFor(model => model.CourseID)
</th>
<th>
@Html.DisplayNameFor(model => model.Title)
</th>
<th>
@Html.DisplayNameFor(model => model.Credits)
</th>
<th>
@Html.DisplayNameFor(model => model.Department)
</th>
<th></th>
</tr>
</thead>
<tbody>
@foreach (var item in Model)
{
<tr>
<td>
@Html.DisplayFor(modelItem => item.CourseID)
</td>
<td>
@Html.DisplayFor(modelItem => item.Title)
</td>
<td>
@Html.DisplayFor(modelItem => item.Credits)
</td>
<td>
@Html.DisplayFor(modelItem => item.Department.Name)
</td>
<td>
<a asp-action="Edit" asp-route-id="@item.CourseID">Edit</a> |
<a asp-action="Details" asp-route-id="@item.CourseID">Details</a> |
<a asp-action="Delete" asp-route-id="@item.CourseID">Delete</a>
</td>
</tr>
}
</tbody>
</table>
Wprowadzono następujące zmiany w kodzie szkieletowym:
Zmieniono nagłówek z Indeks na Kursy.
Dodano kolumnę Number (Liczba ), która pokazuje
CourseID
wartość właściwości. Domyślnie klucze podstawowe nie są szkieletowe, ponieważ zwykle są one bez znaczenia dla użytkowników końcowych. Jednak w tym przypadku klucz podstawowy jest zrozumiały i chcesz go pokazać.Zmieniono kolumnę Department (Dział), aby wyświetlić nazwę działu. Kod wyświetla
Name
właściwośćDepartment
jednostki załadowanej doDepartment
właściwości nawigacji:@Html.DisplayFor(modelItem => item.Department.Name)
Uruchom aplikację i wybierz kartę Kursy , aby wyświetlić listę z nazwami działów.
Tworzenie strony Instruktorzy
W tej sekcji utworzysz kontroler i widok dla Instructor
jednostki, aby wyświetlić stronę Instruktorzy:
Ta strona odczytuje i wyświetla powiązane dane w następujący sposób:
Lista instruktorów zawiera powiązane dane z
OfficeAssignment
jednostki. JednostkiInstructor
iOfficeAssignment
znajdują się w relacji jeden do zera lub jednego. Użyjesz chętnegoOfficeAssignment
ładowania dla jednostek. Jak wyjaśniono wcześniej, ładowanie chętne jest zwykle bardziej wydajne, gdy potrzebne są powiązane dane dla wszystkich pobranych wierszy tabeli podstawowej. W takim przypadku chcesz wyświetlić przydziały biurowe dla wszystkich wyświetlanych instruktorów.Gdy użytkownik wybierze instruktora, zostaną wyświetlone powiązane
Course
jednostki. JednostkiInstructor
iCourse
znajdują się w relacji wiele do wielu. Użyjesz chętnegoCourse
ładowania dla jednostek i powiązanych zDepartment
nimi jednostek. W takim przypadku oddzielne zapytania mogą być bardziej wydajne, ponieważ potrzebne są kursy tylko dla wybranego instruktora. Jednak w tym przykładzie pokazano, jak używać chętnego ładowania do właściwości nawigacji w ramach samych jednostek we właściwościach nawigacji.Gdy użytkownik wybierze kurs, zostaną wyświetlone powiązane dane z
Enrollments
zestawu jednostek. JednostkiCourse
iEnrollment
znajdują się w relacji jeden do wielu. Użyjesz oddzielnych zapytań dlaEnrollment
jednostek i powiązanych zStudent
nimi jednostek.
Tworzenie modelu widoku dla widoku Indeks instruktora
Na stronie Instruktorzy są wyświetlane dane z trzech różnych tabel. W związku z tym utworzysz model widoku zawierający trzy właściwości, z których każda przechowuje dane dla jednej z tabel.
W folderze SchoolViewModels utwórz InstructorIndexData.cs
i zastąp istniejący kod następującym kodem:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace ContosoUniversity.Models.SchoolViewModels
{
public class InstructorIndexData
{
public IEnumerable<Instructor> Instructors { get; set; }
public IEnumerable<Course> Courses { get; set; }
public IEnumerable<Enrollment> Enrollments { get; set; }
}
}
Tworzenie kontrolera instruktora i widoków
Utwórz kontroler instruktorów z akcjami odczytu/zapisu ef, jak pokazano na poniższej ilustracji:
Otwórz InstructorsController.cs
i dodaj instrukcję using dla przestrzeni nazw ViewModels:
using ContosoUniversity.Models.SchoolViewModels;
Zastąp metodę Index następującym kodem, aby wykonać chętne ładowanie powiązanych danych i umieścić ją w modelu widoku.
public async Task<IActionResult> Index(int? id, int? courseID)
{
var viewModel = new InstructorIndexData();
viewModel.Instructors = await _context.Instructors
.Include(i => i.OfficeAssignment)
.Include(i => i.CourseAssignments)
.ThenInclude(i => i.Course)
.ThenInclude(i => i.Enrollments)
.ThenInclude(i => i.Student)
.Include(i => i.CourseAssignments)
.ThenInclude(i => i.Course)
.ThenInclude(i => i.Department)
.AsNoTracking()
.OrderBy(i => i.LastName)
.ToListAsync();
if (id != null)
{
ViewData["InstructorID"] = id.Value;
Instructor instructor = viewModel.Instructors.Where(
i => i.ID == id.Value).Single();
viewModel.Courses = instructor.CourseAssignments.Select(s => s.Course);
}
if (courseID != null)
{
ViewData["CourseID"] = courseID.Value;
viewModel.Enrollments = viewModel.Courses.Where(
x => x.CourseID == courseID).Single().Enrollments;
}
return View(viewModel);
}
Metoda akceptuje opcjonalne dane trasy (id
) i parametr ciągu zapytania (courseID
), który udostępnia wartości identyfikatorów wybranego instruktora i wybranego kursu. Parametry są udostępniane przez hiperlinki Wybierz na stronie.
Kod rozpoczyna się od utworzenia wystąpienia modelu widoku i umieszczenie go na liście instruktorów. Kod określa chętne ładowanie dla Instructor.OfficeAssignment
właściwości nawigacji i Instructor.CourseAssignments
. CourseAssignments
We właściwości właściwość Course
jest ładowana, a w jej Enrollments
obrębie są ładowane właściwości i Department
w ramach każdej Enrollment
jednostki, Student
która jest ładowana.
viewModel.Instructors = await _context.Instructors
.Include(i => i.OfficeAssignment)
.Include(i => i.CourseAssignments)
.ThenInclude(i => i.Course)
.ThenInclude(i => i.Enrollments)
.ThenInclude(i => i.Student)
.Include(i => i.CourseAssignments)
.ThenInclude(i => i.Course)
.ThenInclude(i => i.Department)
.AsNoTracking()
.OrderBy(i => i.LastName)
.ToListAsync();
Ponieważ widok zawsze wymaga OfficeAssignment
jednostki, bardziej wydajne jest pobranie tej jednostki w tym samym zapytaniu. Jednostki kursu są wymagane, gdy instruktor jest wybrany na stronie internetowej, więc pojedyncze zapytanie jest lepsze niż wiele zapytań tylko wtedy, gdy strona jest wyświetlana częściej z wybranym kursem niż bez.
Kod powtarza się CourseAssignments
i Course
dlatego, że potrzebne są dwie właściwości z pliku Course
. Pierwszy ciąg wywołań ThenInclude
pobiera wartości CourseAssignment.Course
, Course.Enrollments
i Enrollment.Student
.
Więcej informacji na temat dołączania wielu poziomów powiązanych danych można znaleźć tutaj.
viewModel.Instructors = await _context.Instructors
.Include(i => i.OfficeAssignment)
.Include(i => i.CourseAssignments)
.ThenInclude(i => i.Course)
.ThenInclude(i => i.Enrollments)
.ThenInclude(i => i.Student)
.Include(i => i.CourseAssignments)
.ThenInclude(i => i.Course)
.ThenInclude(i => i.Department)
.AsNoTracking()
.OrderBy(i => i.LastName)
.ToListAsync();
W tym momencie w kodzie innym ThenInclude
elementem będą właściwości nawigacji , Student
których nie potrzebujesz. Jednak wywołanie Include
zaczyna się od Instructor
właściwości, więc trzeba przejść przez łańcuch ponownie, tym razem określając Course.Department
zamiast Course.Enrollments
.
viewModel.Instructors = await _context.Instructors
.Include(i => i.OfficeAssignment)
.Include(i => i.CourseAssignments)
.ThenInclude(i => i.Course)
.ThenInclude(i => i.Enrollments)
.ThenInclude(i => i.Student)
.Include(i => i.CourseAssignments)
.ThenInclude(i => i.Course)
.ThenInclude(i => i.Department)
.AsNoTracking()
.OrderBy(i => i.LastName)
.ToListAsync();
Poniższy kod jest wykonywany po wybraniu instruktora. Wybrany instruktor jest pobierany z listy instruktorów w modelu widoku. Właściwość modelu Courses
widoku jest następnie ładowana z jednostkami Course
z właściwości nawigacji tego instruktora CourseAssignments
.
if (id != null)
{
ViewData["InstructorID"] = id.Value;
Instructor instructor = viewModel.Instructors.Where(
i => i.ID == id.Value).Single();
viewModel.Courses = instructor.CourseAssignments.Select(s => s.Course);
}
Metoda Where
zwraca kolekcję, ale w tym przypadku kryteria przekazane do tej metody powodują zwrócenie tylko jednej jednostki Instruktor. Metoda Single
konwertuje kolekcję na pojedynczą Instructor
jednostkę, która zapewnia dostęp do właściwości tej CourseAssignments
jednostki. Właściwość CourseAssignments
zawiera CourseAssignment
jednostki, z których chcesz tylko powiązane Course
jednostki.
Metoda jest używana Single
w kolekcji, gdy wiadomo, że kolekcja będzie zawierać tylko jeden element. Metoda Single
zgłasza wyjątek, jeśli kolekcja przekazana do niej jest pusta lub jeśli istnieje więcej niż jeden element. Alternatywą jest SingleOrDefault
, która zwraca wartość domyślną (null w tym przypadku), jeśli kolekcja jest pusta. Jednak w tym przypadku, który nadal powoduje wyjątek (od próby znalezienia Courses
właściwości w odwołaniu o wartości null), a komunikat o wyjątku będzie mniej wyraźnie wskazywać przyczynę problemu. Po wywołaniu Single
metody można również przekazać warunek Where zamiast wywoływać metodę Where
oddzielnie:
.Single(i => i.ID == id.Value)
Zamiast:
.Where(i => i.ID == id.Value).Single()
Następnie, jeśli wybrano kurs, wybrany kurs zostanie pobrany z listy kursów w modelu widoku. Następnie właściwość modelu Enrollments
widoku jest ładowana z jednostkami Enrollment z właściwości nawigacji tego kursu Enrollments
.
if (courseID != null)
{
ViewData["CourseID"] = courseID.Value;
viewModel.Enrollments = viewModel.Courses.Where(
x => x.CourseID == courseID).Single().Enrollments;
}
Śledzenie a brak śledzenia
Zapytania śledzenia nie są przydatne, gdy wyniki są używane w scenariuszu tylko do odczytu. Zazwyczaj są one szybsze do wykonania, ponieważ nie ma potrzeby konfigurowania informacji śledzenia zmian. Jeśli jednostki pobrane z bazy danych nie muszą być aktualizowane, zapytanie śledzenia prawdopodobnie będzie działać lepiej niż zapytanie śledzenia.
W niektórych przypadkach zapytanie śledzenia jest bardziej wydajne niż zapytanie bez śledzenia. Aby uzyskać więcej informacji, zobacz Śledzenie a zapytania bez śledzenia.
Modyfikowanie widoku indeksu instruktora
W Views/Instructors/Index.cshtml
pliku zastąp kod szablonu następującym kodem. Zmiany są wyróżnione.
@model ContosoUniversity.Models.SchoolViewModels.InstructorIndexData
@{
ViewData["Title"] = "Instructors";
}
<h2>Instructors</h2>
<p>
<a asp-action="Create">Create New</a>
</p>
<table class="table">
<thead>
<tr>
<th>Last Name</th>
<th>First Name</th>
<th>Hire Date</th>
<th>Office</th>
<th>Courses</th>
<th></th>
</tr>
</thead>
<tbody>
@foreach (var item in Model.Instructors)
{
string selectedRow = "";
if (item.ID == (int?)ViewData["InstructorID"])
{
selectedRow = "table-success";
}
<tr class="@selectedRow">
<td>
@Html.DisplayFor(modelItem => item.LastName)
</td>
<td>
@Html.DisplayFor(modelItem => item.FirstMidName)
</td>
<td>
@Html.DisplayFor(modelItem => item.HireDate)
</td>
<td>
@if (item.OfficeAssignment != null)
{
@item.OfficeAssignment.Location
}
</td>
<td>
@foreach (var course in item.CourseAssignments)
{
@course.Course.CourseID @course.Course.Title <br />
}
</td>
<td>
<a asp-action="Index" asp-route-id="@item.ID">Select</a> |
<a asp-action="Edit" asp-route-id="@item.ID">Edit</a> |
<a asp-action="Details" asp-route-id="@item.ID">Details</a> |
<a asp-action="Delete" asp-route-id="@item.ID">Delete</a>
</td>
</tr>
}
</tbody>
</table>
@model ContosoUniversity.Models.SchoolViewModels.InstructorIndexData
@{
ViewData["Title"] = "Instructors";
}
<h2>Instructors</h2>
<p>
<a asp-action="Create">Create New</a>
</p>
<table class="table">
<thead>
<tr>
<th>Last Name</th>
<th>First Name</th>
<th>Hire Date</th>
<th>Office</th>
<th>Courses</th>
<th></th>
</tr>
</thead>
<tbody>
@foreach (var item in Model.Instructors)
{
string selectedRow = "";
if (item.ID == (int?)ViewData["InstructorID"])
{
selectedRow = "success";
}
<tr class="@selectedRow">
<td>
@Html.DisplayFor(modelItem => item.LastName)
</td>
<td>
@Html.DisplayFor(modelItem => item.FirstMidName)
</td>
<td>
@Html.DisplayFor(modelItem => item.HireDate)
</td>
<td>
@if (item.OfficeAssignment != null)
{
@item.OfficeAssignment.Location
}
</td>
<td>
@foreach (var course in item.CourseAssignments)
{
@course.Course.CourseID @course.Course.Title <br />
}
</td>
<td>
<a asp-action="Index" asp-route-id="@item.ID">Select</a> |
<a asp-action="Edit" asp-route-id="@item.ID">Edit</a> |
<a asp-action="Details" asp-route-id="@item.ID">Details</a> |
<a asp-action="Delete" asp-route-id="@item.ID">Delete</a>
</td>
</tr>
}
</tbody>
</table>
Wprowadzono następujące zmiany w istniejącym kodzie:
Zmieniono klasę modelu na
InstructorIndexData
.Zmieniono tytuł strony z Indeks na Instruktorzy.
Dodano kolumnę pakietu Office , która jest wyświetlana
item.OfficeAssignment.Location
tylko wtedy, gdyitem.OfficeAssignment
nie ma wartości null. (Ponieważ jest to relacja jeden do zera lub jednego, być może nie ma powiązanej jednostki OfficeAssignment).@if (item.OfficeAssignment != null) { @item.OfficeAssignment.Location }
Dodano kolumnę Kursy zawierającą kursy nauczane przez każdego instruktora. Aby uzyskać więcej informacji, zobacz sekcję Jawne przejście wiersza w Razor artykule składni.
Dodano kod, który warunkowo dodaje klasę CSS Bootstrap do
tr
elementu wybranego instruktora. Ta klasa ustawia kolor tła dla wybranego wiersza.Dodano nowe hiperłącze oznaczone etykietą Wybierz bezpośrednio przed innymi linkami w każdym wierszu, co powoduje wysłanie identyfikatora wybranego
Index
instruktora do metody.<a asp-action="Index" asp-route-id="@item.ID">Select</a> |
Uruchom aplikację i wybierz kartę Instruktorzy . Na stronie jest wyświetlana właściwość Location powiązanych jednostek OfficeAssignment i pusta komórka tabeli, gdy nie ma powiązanej jednostki OfficeAssignment.
Views/Instructors/Index.cshtml
W pliku po zamknięciu elementu tabeli (na końcu pliku) dodaj następujący kod. Ten kod wyświetla listę kursów związanych z instruktorem po wybraniu instruktora.
@if (Model.Courses != null)
{
<h3>Courses Taught by Selected Instructor</h3>
<table class="table">
<tr>
<th></th>
<th>Number</th>
<th>Title</th>
<th>Department</th>
</tr>
@foreach (var item in Model.Courses)
{
string selectedRow = "";
if (item.CourseID == (int?)ViewData["CourseID"])
{
selectedRow = "success";
}
<tr class="@selectedRow">
<td>
@Html.ActionLink("Select", "Index", new { courseID = item.CourseID })
</td>
<td>
@item.CourseID
</td>
<td>
@item.Title
</td>
<td>
@item.Department.Name
</td>
</tr>
}
</table>
}
Ten kod odczytuje Courses
właściwość modelu widoku, aby wyświetlić listę kursów. Zawiera również hiperlink Select , który wysyła identyfikator wybranego kursu do Index
metody akcji.
Odśwież stronę i wybierz instruktora. Teraz zostanie wyświetlona siatka zawierająca kursy przypisane do wybranego instruktora, a dla każdego kursu zostanie wyświetlona nazwa przypisanego działu.
Po dodaniu właśnie dodanego bloku kodu dodaj następujący kod. Spowoduje to wyświetlenie listy uczniów, którzy są zarejestrowani w kursie po wybraniu tego kursu.
@if (Model.Enrollments != null)
{
<h3>
Students Enrolled in Selected Course
</h3>
<table class="table">
<tr>
<th>Name</th>
<th>Grade</th>
</tr>
@foreach (var item in Model.Enrollments)
{
<tr>
<td>
@item.Student.FullName
</td>
<td>
@Html.DisplayFor(modelItem => item.Grade)
</td>
</tr>
}
</table>
}
Ten kod odczytuje Enrollments
właściwość modelu widoku, aby wyświetlić listę uczniów zarejestrowanych w kursie.
Odśwież ponownie stronę i wybierz instruktora. Następnie wybierz kurs, aby wyświetlić listę zarejestrowanych uczniów i ich ocen.
Informacje o jawnym ładowaniu
Po pobraniu listy instruktorów w programie InstructorsController.cs
określono chętne ładowanie dla CourseAssignments
właściwości nawigacji.
Załóżmy, że oczekujesz, że użytkownicy rzadko chcą zobaczyć rejestracje w wybranym instruktorze i kursie. W takim przypadku możesz załadować dane rejestracji tylko wtedy, gdy są wymagane. Aby zobaczyć przykład sposobu jawnego ładowania, zastąp Index
metodę następującym kodem, który usuwa chętne ładowanie i Enrollments
ładuje tę właściwość jawnie. Zmiany kodu są wyróżnione.
public async Task<IActionResult> Index(int? id, int? courseID)
{
var viewModel = new InstructorIndexData();
viewModel.Instructors = await _context.Instructors
.Include(i => i.OfficeAssignment)
.Include(i => i.CourseAssignments)
.ThenInclude(i => i.Course)
.ThenInclude(i => i.Department)
.OrderBy(i => i.LastName)
.ToListAsync();
if (id != null)
{
ViewData["InstructorID"] = id.Value;
Instructor instructor = viewModel.Instructors.Where(
i => i.ID == id.Value).Single();
viewModel.Courses = instructor.CourseAssignments.Select(s => s.Course);
}
if (courseID != null)
{
ViewData["CourseID"] = courseID.Value;
var selectedCourse = viewModel.Courses.Where(x => x.CourseID == courseID).Single();
await _context.Entry(selectedCourse).Collection(x => x.Enrollments).LoadAsync();
foreach (Enrollment enrollment in selectedCourse.Enrollments)
{
await _context.Entry(enrollment).Reference(x => x.Student).LoadAsync();
}
viewModel.Enrollments = selectedCourse.Enrollments;
}
return View(viewModel);
}
Nowy kod usuwa ThenInclude
wywołania metody dla danych rejestracji z kodu pobierającego jednostki instruktora. Spada również AsNoTracking
. Jeśli wybrano instruktora i kurs, wyróżniony kod pobiera Enrollment
jednostki dla wybranego kursu oraz Student
jednostki dla każdego Enrollment
kursu .
Uruchom aplikację, przejdź teraz do strony Indeks instruktorów i nie zobaczysz różnicy w tym, co jest wyświetlane na stronie, chociaż zmieniono sposób pobierania danych.
Uzyskiwanie kodu
Pobierz lub wyświetl ukończoną aplikację.
Następne kroki
W tym samouczku zostały wykonane następujące czynności:
- Dowiedz się, jak ładować powiązane dane
- Utworzono stronę Kursy
- Utworzono stronę Instruktorzy
- Informacje o jawnym ładowaniu
Przejdź do następnego samouczka, aby dowiedzieć się, jak aktualizować powiązane dane.