Tutorial: Lesen verwandter Daten mit EF in einer ASP.NET MVC-App
Im vorherigen Tutorial haben Sie das School-Datenmodell abgeschlossen. In diesem Tutorial lesen und zeigen Sie verwandte Daten an, d. h. Daten, die das Entity Framework in Navigationseigenschaften lädt.
Die folgenden Abbildungen zeigen die Seiten, mit den Sie arbeiten werden.
Abgeschlossenes Projekt herunterladen
Die Contoso University-Beispielwebanwendung veranschaulicht, wie ASP.NET MVC 5-Anwendungen mithilfe von Entity Framework 6 Code First und Visual Studio erstellt werden. Informationen zu dieser Tutorialreihe finden Sie im ersten Tutorial der Reihe.
In diesem Tutorial:
- Erfahren Sie, wie verwandte Daten geladen werden.
- Erstellen Sie eine Seite „Kurse“
- Erstellen Sie eine Seite „Instructors“
Voraussetzungen
Erfahren Sie, wie verwandte Daten geladen werden.
Es gibt mehrere Möglichkeiten, wie Entity Framework verwandte Daten in die Navigationseigenschaften einer Entität laden kann:
Lazy Loading (verzögertes Laden). Wenn die Entität zuerst gelesen wird, werden verwandte Daten nicht abgerufen. Wenn Sie jedoch zum ersten Mal versuchen, auf eine Navigationseigenschaft zuzugreifen, werden die für diese Navigationseigenschaft erforderlichen Daten automatisch abgerufen. Dies führt dazu, dass mehrere Abfragen an die Datenbank gesendet werden – eine für die Entität selbst und eine für jedes Mal, wenn verwandte Daten für die Entität abgerufen werden müssen. Die
DbContext
-Klasse aktiviert standardmäßig verzögertes Laden.Eager Loading (vorzeitiges Laden). Wenn die Entität gelesen wird, werden ihre verwandten Daten mit ihr abgerufen. Dies führt normalerweise zu einer einzelnen Joinabfrage, die alle Daten abruft, die erforderlich sind. Sie geben eager loading mithilfe der
Include
-Methode an.Explizites Laden. Dies ähnelt dem verzögerten Laden, mit der Ausnahme, dass Sie die zugehörigen Daten explizit im Code abrufen. Dies geschieht nicht automatisch, wenn Sie auf eine Navigationseigenschaft zugreifen. Sie laden verknüpfte Daten manuell, indem Sie den Objektzustands-Manager-Eintrag für eine Entität abrufen und die Collection.Load-Methode für Sammlungen oder die Reference.Load-Methode für Eigenschaften aufrufen, die eine einzelne Entität enthalten. (Wenn Sie im folgenden Beispiel die Administratornavigationseigenschaft laden möchten, ersetzen
Collection(x => x.Courses)
Sie durchReference(x => x.Administrator)
.) In der Regel verwenden Sie explizites Laden nur, wenn Sie verzögertes Laden deaktiviert haben.
Da sie die Eigenschaftswerte nicht sofort abrufen, werden verzögertes Laden und explizites Laden auch als verzögertes Laden bezeichnet.
Überlegungen zur Leistung
Wenn Sie wissen, dass Sie für jede abgerufene Entität verwandte Daten benötigen, bietet Eager Loading häufig die beste Leistung, da eine einzelne Abfrage, die an die Datenbank gesendet wird, in der Regel effizienter ist als separate Abfragen für jede abgerufene Entität. Nehmen Sie beispielsweise in den obigen Beispielen an, dass jede Abteilung über zehn verwandte Kurse verfügt. Das Beispiel für das eifrige Laden würde nur zu einer einzelnen (Join-)Abfrage und einem einzelnen Roundtrip zur Datenbank führen. Die Beispiele für verzögertes Laden und explizites Laden würden beide zu elf Abfragen und elf Roundtrips zur Datenbank führen. Die zusätzlichen Roundtrips zur Datenbank beeinträchtigen die Leistung besonders bei hoher Latenz.
Auf der anderen Seite ist in einigen Szenarien das verzögerte Laden effizienter. Beim eifrigen Laden wird möglicherweise eine sehr komplexe Verknüpfung generiert, die SQL Server nicht effizient verarbeiten kann. Oder wenn Sie nur für eine Teilmenge einer Gruppe der von Ihnen verarbeiteten Entitäten auf die Navigationseigenschaften einer Entität zugreifen müssen, kann das verzögerte Laden besser funktionieren, da beim ausführenden Laden mehr Daten abgerufen werden, als Sie benötigen. Wenn die Leistung wichtig ist, empfiehlt es sich, die Leistung mit beiden Möglichkeiten zu testen, um die beste Wahl treffen zu können.
Verzögertes Laden kann Code masken, der Leistungsprobleme verursacht. Beispielsweise kann Code, der kein eager oder explizites Laden angibt, sondern eine große Menge von Entitäten verarbeitet und in jeder Iteration mehrere Navigationseigenschaften verwendet, sehr ineffizient sein (aufgrund vieler Roundtrips zur Datenbank). Eine Anwendung, die bei der Entwicklung mit einer lokalen SQL Server-Instanz eine gute Leistung erzielt, kann aufgrund der erhöhten Latenz und der verzögerten Ladevorgänge leistungsprobleme auftreten, wenn sie in Azure SQL-Datenbank verschoben wird. Durch die Profilerstellung der Datenbankabfragen mit einer realistischen Testauslastung können Sie ermitteln, ob verzögertes Laden geeignet ist. Weitere Informationen finden Sie unter Entmystifying Entity Framework Strategies: Loading Related Data und Using the Entity Framework to Reduce Network Latency to SQL Azure.
Deaktivieren des verzögerten Ladens vor der Serialisierung
Wenn Sie das verzögerte Laden während der Serialisierung aktiviert lassen, können Sie am Ende deutlich mehr Daten abfragen, als Sie beabsichtigt haben. Die Serialisierung funktioniert in der Regel, indem auf jede Eigenschaft eines instance eines Typs zugegriffen wird. Der Eigenschaftszugriff löst verzögertes Laden aus, und diese verzögert geladenen Entitäten werden serialisiert. Der Serialisierungsprozess greift dann auf jede Eigenschaft der verzögert geladenen Entitäten zu, was möglicherweise zu noch mehr verzögertem Laden und Serialisieren führt. Um diese Ablaufkettenreaktion zu verhindern, schalten Sie das verzögerte Laden aus, bevor Sie eine Entität serialisieren.
Die Serialisierung kann auch durch die Proxyklassen kompliziert werden, die von Entity Framework verwendet werden, wie im Tutorial zu erweiterten Szenarien erläutert.
Eine Möglichkeit, Serialisierungsprobleme zu vermeiden, besteht darin, Datenübertragungsobjekte (Data Transfer Objects, DTOs) anstelle von Entitätsobjekten zu serialisieren, wie im Tutorial Verwenden der Web-API mit Entity Framework gezeigt.
Wenn Sie keine DTOs verwenden, können Sie verzögertes Laden deaktivieren und Proxyprobleme vermeiden, indem Sie die Proxyerstellung deaktivieren.
Hier sind einige andere Möglichkeiten, um verzögertes Laden zu deaktivieren:
Lassen Sie bei bestimmten Navigationseigenschaften die
virtual
Schlüsselwort (keyword) aus, wenn Sie die Eigenschaft deklarieren.Legen Sie für alle Navigationseigenschaften auf
false
festLazyLoadingEnabled
, fügen Sie den folgenden Code in den Konstruktor Ihrer Kontextklasse ein:this.Configuration.LazyLoadingEnabled = false;
Erstellen Sie eine Seite „Kurse“
Die Entität Course
enthält eine Navigationseigenschaft, die die Department
-Entität der Abteilung enthält, der der Kurs zugewiesen ist. Um den Namen der zugewiesenen Abteilung in einer Liste von Kursen anzuzeigen, müssen Sie die Name
-Eigenschaft von der Department
Entität abrufen, die sich in der Course.Department
Navigationseigenschaft befindet.
Erstellen Sie einen Controller mit dem Namen CourseController
(nicht CoursesController) für den Course
Entitätstyp, und verwenden Sie dabei die gleichen Optionen für den MVC 5-Controller mit Ansichten, und verwenden Sie das Entity Framework-Gerüst , das Sie zuvor für den Student
Controller ausgeführt haben:
Einstellung | Wert |
---|---|
Model-Klasse | Wählen Sie Kurs (ContosoUniversity.Models) aus. |
Datenkontextklasse | Wählen Sie SchoolContext (ContosoUniversity.DAL) aus. |
Controllername | Geben Sie CourseController ein. Auch hier nicht CoursesController mit einem s. Wenn Sie Kurs (ContosoUniversity.Models) ausgewählt haben, wurde der Wert des Controllernamens automatisch aufgefüllt. Sie müssen den Wert ändern. |
Behalten Sie die anderen Standardwerte bei, und fügen Sie den Controller hinzu.
Öffnen Sie Controllers\CourseController.cs , und sehen Sie sich die Methode an Index
:
public ActionResult Index()
{
var courses = db.Courses.Include(c => c.Department);
return View(courses.ToList());
}
Der automatische Gerüstbau hat mithilfe der Include
-Methode ein Eager Loading für die Department
-Navigationseigenschaft angegeben.
Öffnen Sie Views\Course\Index.cshtml, und ersetzen Sie den Vorlagencode durch den folgenden Code. Die Änderungen werden hervorgehoben:
@model IEnumerable<ContosoUniversity.Models.Course>
@{
ViewBag.Title = "Courses";
}
<h2>Courses</h2>
<p>
@Html.ActionLink("Create New", "Create")
</p>
<table class="table">
<tr>
<th>
@Html.DisplayNameFor(model => model.CourseID)
</th>
<th>
@Html.DisplayNameFor(model => model.Title)
</th>
<th>
@Html.DisplayNameFor(model => model.Credits)
</th>
<th>
Department
</th>
<th></th>
</tr>
@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>
@Html.ActionLink("Edit", "Edit", new { id=item.CourseID }) |
@Html.ActionLink("Details", "Details", new { id=item.CourseID }) |
@Html.ActionLink("Delete", "Delete", new { id=item.CourseID })
</td>
</tr>
}
</table>
Sie haben die folgenden Änderungen am eingerüsteten Code vorgenommen:
- Die Überschrift wurde von Index in Courses geändert.
- Die Spalte Anzahl wurde hinzugefügt. Sie zeigt den
CourseID
-Eigenschaftswert an. Primärschlüssel sind standardmäßig nicht gerüstet, da sie normalerweise für Endbenutzer bedeutungslos sind. Allerdings ist in diesem Fall der Primärschlüssel sinnvoll, und Sie möchten ihn anzeigen. - Die Spalte Abteilung wurde nach rechts verschoben, und die Überschrift wurde geändert. Das Gerüst hat richtig ausgewählt, um die
Name
Eigenschaft aus derDepartment
Entität anzuzeigen, aber hier auf der Kursseite sollte die Spaltenüberschrift Abteilung und nicht Name lauten.
Beachten Sie, dass für die Spalte Abteilung im Gerüstcode die Name
Eigenschaft der Entität angezeigt wird, die Department
in die Department
Navigationseigenschaft geladen wird:
<td>
@Html.DisplayFor(modelItem => item.Department.Name)
</td>
Führen Sie die Seite aus (wählen Sie auf der Startseite der Contoso University die Registerkarte Kurse aus), um die Liste mit den Abteilungsnamen anzuzeigen.
Erstellen Sie eine Seite „Instructors“
In diesem Abschnitt erstellen Sie einen Controller und eine Ansicht für die Instructor
Entität, um die Seite Dozenten anzuzeigen. Auf dieser Seite werden verwandte Daten auf folgende Weise gelesen und angezeigt:
- Die Liste der Lehrkräfte zeigt zugehörige Daten aus der Entität
OfficeAssignment
an. DieInstructor
- undOfficeAssignment
-Entitäten stehen in einer 1:0..1-Beziehung zueinander. Für dieOfficeAssignment
-Entitäten verwenden Sie das Eager Loading. Wie zuvor erläutert, ist Eager Loading in der Regel effizienter, wenn Sie die verwandten Daten für alle abgerufenen Zeilen der primären Tabelle benötigen. In diesem Fall sollten Sie die Office-Anweisungen für alle angezeigten Dozenten anzeigen. - Wenn der Benutzer einen Dozenten auswählt, werden zugehörige
Course
-Entitäten angezeigt. DieInstructor
- undCourse
-Entitäten stehen in einer m:n-Beziehung zueinander. Für dieCourse
-Entitäten und die zugehörigenDepartment
-Entitäten verwenden Sie das Eager Loading. In diesem Fall kann das faule Laden effizienter sein, da Sie Kurse nur für den ausgewählten Kursleiter benötigen. Dieses Beispiel zeigt jedoch, wie Eager Loading für Navigationseigenschaften in Entitäten in den Navigationseigenschaften verwendet wird. - Wenn der Benutzer einen Kurs auswählt, werden zugehörige Daten aus der Entitätenmenge
Enrollments
angezeigt. DieCourse
- undEnrollment
-Entitäten stehen in einer 1:n-Beziehung zueinander. Sie fügen explizites Laden fürEnrollment
Entitäten und die zugehörigenStudent
Entitäten hinzu. (Explizites Laden ist nicht erforderlich, da das verzögerte Laden aktiviert ist, aber dies zeigt, wie explizit geladen wird.)
Erstellen eines Ansichtsmodells für die Kursleiterindexansicht
Auf der Seite "Kursleiter" werden drei verschiedene Tabellen angezeigt. Aus diesem Grund erstellen Sie ein Ansichtsmodell, das drei Eigenschaften enthält. Jede enthält Daten für eine der Tabellen.
Erstellen Sie im Ordner ViewModelsInstructorIndexData.cs , und ersetzen Sie den vorhandenen Code durch den folgenden Code:
using System.Collections.Generic;
using ContosoUniversity.Models;
namespace ContosoUniversity.ViewModels
{
public class InstructorIndexData
{
public IEnumerable<Instructor> Instructors { get; set; }
public IEnumerable<Course> Courses { get; set; }
public IEnumerable<Enrollment> Enrollments { get; set; }
}
}
Erstellen des Kursleitercontrollers und der Ansichten
Erstellen Sie einen InstructorController
Controller (nicht InstructorsController) mit EF-Lese-/Schreibaktion:
Einstellung | Wert |
---|---|
Model-Klasse | Wählen Sie Instructor (ContosoUniversity.Models) aus. |
Datenkontextklasse | Wählen Sie SchoolContext (ContosoUniversity.DAL) aus. |
Controllername | Geben Sie InstructorController ein. Auch hier nicht InstructorsController mit einem s. Wenn Sie Kurs (ContosoUniversity.Models) ausgewählt haben, wurde der Wert des Controllernamens automatisch aufgefüllt. Sie müssen den Wert ändern. |
Behalten Sie die anderen Standardwerte bei, und fügen Sie den Controller hinzu.
Öffnen Sie Controllers\InstructorController.cs , und fügen Sie eine using
Anweisung für den ViewModels
Namespace hinzu:
using ContosoUniversity.ViewModels;
Der Gerüstcode in der Index
-Methode gibt das laden nur für die OfficeAssignment
Navigationseigenschaft an:
public ActionResult Index()
{
var instructors = db.Instructors.Include(i => i.OfficeAssignment);
return View(instructors.ToList());
}
Ersetzen Sie die Index
-Methode durch den folgenden Code, um zusätzliche verwandte Daten zu laden, und fügen Sie sie in das Ansichtsmodell ein:
public ActionResult Index(int? id, int? courseID)
{
var viewModel = new InstructorIndexData();
viewModel.Instructors = db.Instructors
.Include(i => i.OfficeAssignment)
.Include(i => i.Courses.Select(c => c.Department))
.OrderBy(i => i.LastName);
if (id != null)
{
ViewBag.InstructorID = id.Value;
viewModel.Courses = viewModel.Instructors.Where(
i => i.ID == id.Value).Single().Courses;
}
if (courseID != null)
{
ViewBag.CourseID = courseID.Value;
viewModel.Enrollments = viewModel.Courses.Where(
x => x.CourseID == courseID).Single().Enrollments;
}
return View(viewModel);
}
Die Methode akzeptiert optionale Routendaten (id
) und einen Abfragezeichenfolgenparameter (courseID
), die die ID-Werte des ausgewählten Kursleiters und des ausgewählten Kurses bereitstellen, und übergibt alle erforderlichen Daten an die Ansicht. Die Parameter werden durch die Auswählen-Links auf der Seite bereitgestellt.
Der Code erstellt zuerst eine Instanz des Ansichtsmodells und fügt die Dozentenliste ein. Der Code gibt das eifrige Laden für die Instructor.OfficeAssignment
Navigationseigenschaft und an Instructor.Courses
.
var viewModel = new InstructorIndexData();
viewModel.Instructors = db.Instructors
.Include(i => i.OfficeAssignment)
.Include(i => i.Courses.Select(c => c.Department))
.OrderBy(i => i.LastName);
Die zweite Include
Methode lädt Kurse, und für jeden geladenen Kurs wird eifrig für die Course.Department
Navigationseigenschaft geladen.
.Include(i => i.Courses.Select(c => c.Department))
Wie bereits erwähnt, ist ein eifriger Ladevorgang nicht erforderlich, aber es wird getan, um die Leistung zu verbessern. Da für die Ansicht immer die Entität OfficeAssignment
erforderlich ist, ist es effizienter, sie in derselben Abfrage abzurufen. Course
Entitäten sind erforderlich, wenn ein Kursleiter auf der Webseite ausgewählt wird. Daher ist eifriges Laden besser als verzögertes Laden nur dann, wenn die Seite häufiger mit einem ausgewählten Kurs als ohne angezeigt wird.
Wenn eine Kursleiter-ID ausgewählt wurde, wird der ausgewählte Kursleiter aus der Liste der Kursleiter im Ansichtsmodell abgerufen. Die Eigenschaft Courses
des Ansichtsmodells wird dann mit den Course
-Entitäten aus der Navigationseigenschaft Courses
dieser Lehrkraft geladen.
if (id != null)
{
ViewBag.InstructorID = id.Value;
viewModel.Courses = viewModel.Instructors.Where(i => i.ID == id.Value).Single().Courses;
}
Die Where
Methode gibt eine Auflistung zurück, aber in diesem Fall führen die an diese Methode übergebenen Kriterien dazu, dass nur eine einzelne Instructor
Entität zurückgegeben wird. Die Methode Single
konvertiert die Sammlung in eine einzelne Instructor
-Entität, die Ihnen Zugriff auf die Courses
-Eigenschaft dieser Entität erteilt.
Sie verwenden die Single-Methode für eine Auflistung, wenn Sie wissen, dass die Auflistung nur ein Element enthält. Die Single
-Methode löst eine Ausnahme aus, wenn die an sie übergebene Auflistung leer ist oder wenn mehrere Elemente vorhanden sind. Eine Alternative ist SingleOrDefault, der einen Standardwert (null
in diesem Fall) zurückgibt, wenn die Auflistung leer ist. In diesem Fall würde dies jedoch zu einer Ausnahme führen (wenn versucht wird, eine Courses
Eigenschaft für einen null
Verweis zu finden), und die Ausnahmemeldung würde weniger eindeutig auf die Ursache des Problems hinweisen. Wenn Sie die Single
-Methode aufrufen, können Sie die Where
Bedingung auch übergeben, anstatt die Where
Methode separat aufzurufen:
.Single(i => i.ID == id.Value)
anstelle von:
.Where(I => i.ID == id.Value).Single()
Wenn ein Kurs ausgewählt wurde, wird der ausgewählte Kurs aus der Kursliste im Ansichtsmodell abgerufen. Anschließend wird die Eigenschaft des Ansichtsmodells Enrollments
mit den Entitäten aus der Enrollment
Navigationseigenschaft dieses Kurses Enrollments
geladen.
if (courseID != null)
{
ViewBag.CourseID = courseID.Value;
viewModel.Enrollments = viewModel.Courses.Where(
x => x.CourseID == courseID).Single().Enrollments;
}
Ändern der Kursleiterindexansicht
Ersetzen Sie in Views\Instructor\Index.cshtml den Vorlagencode durch den folgenden Code. Die Änderungen werden hervorgehoben:
@model ContosoUniversity.ViewModels.InstructorIndexData
@{
ViewBag.Title = "Instructors";
}
<h2>Instructors</h2>
<p>
@Html.ActionLink("Create New", "Create")
</p>
<table class="table">
<tr>
<th>Last Name</th>
<th>First Name</th>
<th>Hire Date</th>
<th>Office</th>
<th></th>
</tr>
@foreach (var item in Model.Instructors)
{
string selectedRow = "";
if (item.ID == ViewBag.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>
@Html.ActionLink("Select", "Index", new { id = item.ID }) |
@Html.ActionLink("Edit", "Edit", new { id = item.ID }) |
@Html.ActionLink("Details", "Details", new { id = item.ID }) |
@Html.ActionLink("Delete", "Delete", new { id = item.ID })
</td>
</tr>
}
</table>
Sie haben die folgenden Änderungen am bestehenden Code vorgenommen:
Die Modellklasse wurde zu
InstructorIndexData
geändert.Der Seitenname wurde von Index in Dozenten geändert.
Eine Office-Spalte wurde hinzugefügt, die nur angezeigt wird
item.OfficeAssignment.Location
, wennitem.OfficeAssignment
nicht NULL ist. (Da es sich hierbei um eine 1:1-Beziehung handelt, gibt es möglicherweise keine verwandteOfficeAssignment
Entität.)<td> @if (item.OfficeAssignment != null) { @item.OfficeAssignment.Location } </td>
Code hinzugefügt, der dem
tr
Element des ausgewählten Kursleiters dynamisch hinzugefügtclass="success"
wird. Dadurch wird eine Hintergrundfarbe für die ausgewählte Zeile mithilfe einer Bootstrap-Klasse festgelegt.string selectedRow = ""; if (item.InstructorID == ViewBag.InstructorID) { selectedRow = "success"; } <tr class="@selectedRow" valign="top">
Die neue
ActionLink
Bezeichnung Select direkt vor den anderen Links in jeder Zeile wurde hinzugefügt, wodurch die ausgewählte Kursleiter-ID an dieIndex
-Methode gesendet wird.
Führen Sie die Anwendung aus, und wählen Sie die Registerkarte Dozenten aus. Die Seite zeigt die Location
Eigenschaft verwandter OfficeAssignment
Entitäten und eine leere Tabellenzelle an, wenn keine zugehörige OfficeAssignment
Entität vorhanden ist.
Fügen Sie in der Datei Views\Instructor\Index.cshtml nach dem schließenden table
Element (am Ende der Datei) den folgenden Code hinzu. Dieser Code zeigt eine Liste der Kurse an, die im Zusammenhang mit einem Dozenten stehen, wenn ein Dozent ausgewählt wird.
@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 == ViewBag.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>
}
Dieser Code liest die Courses
-Eigenschaft des Ansichtsmodells, um eine Kursliste anzuzeigen. Außerdem wird ein Select
Link bereitgestellt, der die ID des ausgewählten Kurses an die Index
Aktionsmethode sendet.
Führen Sie die Seite aus, und wählen Sie einen Kursleiter aus. Jetzt sehen Sie ein Raster, das die dem Dozenten zugewiesenen Kurse anzeigt. Sie sehen auch den Namen der zugewiesenen Abteilung für jeden Kurs.
Fügen Sie den folgenden Code hinzu, nachdem Sie den Codeblock hinzugefügt haben. Dies zeigt eine Liste der Studenten an, die im Kurs registriert sind, wenn dieser Kurs ausgewählt ist.
@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>
}
Dieser Code liest die Eigenschaft Enrollments
des Ansichtsmodells, um eine Liste der in diesem Kurs registrierten Studierenden anzuzeigen.
Führen Sie die Seite aus, und wählen Sie einen Kursleiter aus. Wählen Sie dann einen Kurs aus, um die Liste der registrierten Studenten und deren Noten einzusehen.
Explizites Laden hinzufügen
Öffnen Sie InstructorController.cs , und sehen Sie sich an, wie die Index
Methode die Liste der Registrierungen für einen ausgewählten Kurs abruft:
if (courseID != null)
{
ViewBag.CourseID = courseID.Value;
viewModel.Enrollments = viewModel.Courses.Where(
x => x.CourseID == courseID).Single().Enrollments;
}
Als Sie die Liste der Kursleiter abgerufen haben, haben Sie eifrig geladen für die Courses
Navigationseigenschaft und die Department
Eigenschaft jedes Kurses angegeben. Anschließend fügen Sie die Courses
Auflistung in das Ansichtsmodell ein, und jetzt greifen Sie von einer Entität in dieser Auflistung auf die Enrollments
Navigationseigenschaft zu. Da Sie für die Course.Enrollments
Navigationseigenschaft kein eifriges Laden angegeben haben, werden die Daten aus dieser Eigenschaft aufgrund des verzögerten Ladens auf der Seite angezeigt.
Wenn Sie das verzögerte Laden deaktiviert haben, ohne den Code auf andere Weise zu ändern, ist die Enrollments
Eigenschaft null, unabhängig davon, wie viele Registrierungen der Kurs tatsächlich hatte. In diesem Fall müssen Sie zum Laden der Enrollments
Eigenschaft entweder eifrig oder explizites Laden angeben. Sie haben bereits gesehen, wie Sie eifrig laden. Um ein Beispiel für das explizite Laden anzuzeigen, ersetzen Sie die Index
-Methode durch den folgenden Code, der die Enrollments
Eigenschaft explizit lädt. Der geänderte Code wird hervorgehoben.
public ActionResult Index(int? id, int? courseID)
{
var viewModel = new InstructorIndexData();
viewModel.Instructors = db.Instructors
.Include(i => i.OfficeAssignment)
.Include(i => i.Courses.Select(c => c.Department))
.OrderBy(i => i.LastName);
if (id != null)
{
ViewBag.InstructorID = id.Value;
viewModel.Courses = viewModel.Instructors.Where(
i => i.ID == id.Value).Single().Courses;
}
if (courseID != null)
{
ViewBag.CourseID = courseID.Value;
// Lazy loading
//viewModel.Enrollments = viewModel.Courses.Where(
// x => x.CourseID == courseID).Single().Enrollments;
// Explicit loading
var selectedCourse = viewModel.Courses.Where(x => x.CourseID == courseID).Single();
db.Entry(selectedCourse).Collection(x => x.Enrollments).Load();
foreach (Enrollment enrollment in selectedCourse.Enrollments)
{
db.Entry(enrollment).Reference(x => x.Student).Load();
}
viewModel.Enrollments = selectedCourse.Enrollments;
}
return View(viewModel);
}
Nach dem Abrufen der ausgewählten Course
Entität lädt der neue Code explizit die Navigationseigenschaft dieses Kurses Enrollments
:
db.Entry(selectedCourse).Collection(x => x.Enrollments).Load();
Anschließend wird explizit die zugehörige Student
Entität jeder Enrollment
Entität geladen:
db.Entry(enrollment).Reference(x => x.Student).Load();
Beachten Sie, dass Sie die Collection
-Methode verwenden, um eine Sammlungseigenschaft zu laden, aber für eine Eigenschaft, die nur eine Entität enthält, verwenden Sie die Reference
-Methode.
Führen Sie jetzt die Seite Kursleiterindex aus, und Sie sehen keinen Unterschied in der Anzeige auf der Seite, obwohl Sie geändert haben, wie die Daten abgerufen werden.
Abrufen des Codes
Abgeschlossenes Projekt herunterladen
Zusätzliche Ressourcen
Links zu anderen Entity Framework-Ressourcen finden Sie im ASP.NET Datenzugriff – Empfohlene Ressourcen.
Nächste Schritte
In diesem Tutorial:
- Haben Sie gelernt, wie verwandte Daten geladen werden
- Wurde eine Seite „Kurse“ erstellt
- Wurde eine Seite „Instructors“ erstellt
Wechseln Sie zum nächsten Artikel, um mehr über das Aktualisieren zugehöriger Daten zu erfahren.
Feedback
https://aka.ms/ContentUserFeedback.
Bald verfügbar: Im Laufe des Jahres 2024 werden wir GitHub-Issues stufenweise als Feedbackmechanismus für Inhalte abbauen und durch ein neues Feedbacksystem ersetzen. Weitere Informationen finden Sie unterFeedback senden und anzeigen für