Lesen verwandter Daten mit dem Entity Framework in einer ASP.NET MVC-Anwendung (5 von 10)
von Tom Dykstra
Die Contoso University-Beispielwebanwendung veranschaulicht, wie Sie ASP.NET MVC 4-Anwendungen mithilfe von Entity Framework 5 Code First und Visual Studio 2012 erstellen. Informationen zu dieser Tutorialreihe finden Sie im ersten Tutorial der Reihe.
Hinweis
Wenn ein Problem auftritt, das nicht behoben werden kann, laden Sie das abgeschlossene Kapitel herunter , und versuchen Sie, das Problem zu reproduzieren. Im Allgemeinen können Sie die Lösung für das Problem finden, indem Sie Ihren Code mit dem abgeschlossenen Code vergleichen. Einige häufige Fehler und deren Behebung finden Sie unter Fehler und Problemumgehungen.
Im vorherigen Tutorial haben Sie das Schuldatenmodell abgeschlossen. In diesem Tutorial lesen und zeigen Sie verwandte Daten an, d. h. Daten, die vom Entity Framework in Navigationseigenschaften geladen werden.
Die folgenden Abbildungen zeigen die Seiten, mit den Sie arbeiten werden.
Verzögertes, eifriges und explizites Laden verwandter Daten
Es gibt mehrere Möglichkeiten, wie das 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 zu mehreren Abfragen, die an die Datenbank gesendet werden – eine für die Entität selbst und eine, die jedes Mal verknüpfte Daten für die Entität abgerufen werden müssen.
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 mit der
Include
-Methode "Eager Loading" 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 verwandte Daten manuell, indem Sie den Objektstatus-Manager-Eintrag für eine Entität abrufen und die
Collection.Load
Methode für Sammlungen oder die Methode für Eigenschaften aufrufen, dieReference.Load
eine einzelne Entität enthalten. (Wenn Sie im folgenden Beispiel die Administratornavigationseigenschaft laden möchten, ersetzenCollection(x => x.Courses)
Sie durchReference(x => x.Administrator)
.)
Da die Eigenschaftswerte nicht sofort abgerufen werden, werden verzögertes Laden und explizites Laden auch als verzögertes Laden bezeichnet.
Im Allgemeinen, wenn Sie wissen, dass Sie verwandte Daten für jede abgerufene Entität benötigen, bietet das eifrige Laden 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 Abfrage (Join) und einem einzelnen Roundtrip zur Datenbank führen. Die Beispiele für verzögertes Laden und explizites Laden würden 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 lazy 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 von Entitäten, die Sie verarbeiten, auf die Navigationseigenschaften einer Entität zugreifen müssen, kann das verzögerte Laden besser funktionieren, da beim eifrigen 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.
In der Regel verwenden Sie explizites Laden nur, wenn Sie das verzögerte Laden deaktiviert haben. Ein Szenario, in dem Sie das verzögerte Laden deaktivieren sollten, ist während der Serialisierung. Lazy loading and serialization funktionieren nicht gut, und wenn Sie nicht vorsichtig sind, können Sie am Ende deutlich mehr Daten abfragen, als Sie beabsichtigt haben, wenn das verzögerte Laden aktiviert ist. Die Serialisierung funktioniert in der Regel durch Zugriff auf jede Eigenschaft auf einem instance eines Typs. Der Eigenschaftenzugriff löst das verzögerte Laden aus, und diese lazy geladenen Entitäten werden serialisiert. Der Serialisierungsprozess greift dann auf jede Eigenschaft der lazy geladenen Entitäten zu, was möglicherweise zu noch mehr Verzögertem Laden und Serialisieren führt. Um diese Verkettungsreaktion zu verhindern, schalten Sie das verzögerte Laden aus, bevor Sie eine Entität serialisieren.
Die Datenbankkontextklasse führt standardmäßig verzögertes Laden aus. Es gibt zwei Möglichkeiten, das verzögerte Laden zu deaktivieren:
Lassen Sie bei bestimmten Navigationseigenschaften die
virtual
Schlüsselwort (keyword) weg, wenn Sie die Eigenschaft deklarieren.Legen Sie für alle Navigationseigenschaften auf
false
festLazyLoadingEnabled
. Beispielsweise können Sie den folgenden Code in den Konstruktor Ihrer Kontextklasse einfügen:this.Configuration.LazyLoadingEnabled = false;
Verzögertes Laden kann Code masken, der Leistungsprobleme verursacht. Code, der z. B. kein eifriges oder explizites Laden angibt, sondern eine große Menge von Entitäten verarbeitet und mehrere Navigationseigenschaften in jeder Iteration verwendet, kann sehr ineffizient sein (aufgrund vieler Roundtrips zur Datenbank). Eine Anwendung, die bei der Entwicklung mit einem lokalen SQL Server gut abschneidet, kann aufgrund der erhöhten Latenz und des verzögerten Ladens zu Azure SQL Datenbank zu Leistungsproblemen führen. Durch die Profilerstellung der Datenbankabfragen mit einer realistischen Testauslastung können Sie ermitteln, ob das verzögerte Laden angemessen ist. Weitere Informationen finden Sie unter Entmystifizieren von Entity Framework-Strategien: Laden verwandter Daten und Verwenden des Entity Frameworks zum Reduzieren der Netzwerklatenz auf SQL Azure.
Erstellen einer Kursindexseite mit Abteilungsname
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 namens CourseController
für den Course
Entitätstyp, und verwenden Sie die gleichen Optionen wie zuvor für den Student
Controller, wie in der folgenden Abbildung gezeigt (außer, dass sich Ihre Kontextklasse im DAL-Namespace befindet, nicht im Models-Namespace):
Öffnen Sie Controller\CourseController.cs , und sehen Sie sich die Methode an Index
:
public ViewResult 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 vorhandenen Code 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>
<tr>
<th></th>
<th>Number</th>
<th>Title</th>
<th>Credits</th>
<th>Department</th>
</tr>
@foreach (var item in Model) {
<tr>
<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>
<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>
</tr>
}
</table>
Sie haben die folgenden Änderungen am eingerüsteten Code vorgenommen:
- Die Überschrift wurde von Index in Courses geändert.
- Die Zeilenlinks wurden nach links verschoben.
- Unter der Überschrift Zahl wurde eine Spalte hinzugefügt, die den
CourseID
Eigenschaftswert anzeigt. (Primärschlüssel sind standardmäßig nicht gerüstet, da sie normalerweise für Endbenutzer bedeutungslos sind. In diesem Fall ist der Primärschlüssel jedoch sinnvoll, und Sie möchten ihn anzeigen.) - Die letzte Spaltenüberschrift wurde von DepartmentID (der Name des Fremdschlüssels der Entität) in
Department
Department geändert.
Beachten Sie, dass der Gerüstcode für die letzte Spalte die Name
Eigenschaft der Entität anzeigt, 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 einer Kursleiterindexseite mit Kursen und Registrierungen
In diesem Abschnitt erstellen Sie einen Controller und eine Ansicht für die Instructor
Entität, um die Seite Kursleiterindex 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 Kursleiterindex 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; }
}
}
Hinzufügen eines Stils für ausgewählte Zeilen
Um ausgewählte Zeilen zu markieren, benötigen Sie eine andere Hintergrundfarbe. Um eine Formatvorlage für diese Benutzeroberfläche bereitzustellen, fügen Sie den folgenden hervorgehobenen Code zum Abschnitt /* info and errors */
in Content\Site.css hinzu, wie unten gezeigt:
/* info and errors */
.selectedrow
{
background-color: #a4d4e6;
}
.message-info {
border: 1px solid;
clear: both;
padding: 10px 20px;
}
Erstellen des Dozentencontrollers und der Ansichten
Erstellen Sie einen InstructorController
Controller, wie in der folgenden Abbildung gezeigt:
Öffnen Sie Controllers\InstructorController.cs , und fügen Sie eine using
Anweisung für den ViewModels
Namespace hinzu:
using ContosoUniversity.ViewModels;
Der gerüstete Code in der Index
-Methode gibt eager loading nur für die OfficeAssignment
Navigationseigenschaft an:
public ViewResult 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 im Ansichtsmodell zu platzieren:
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.InstructorID == 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 angeben, und übergibt alle erforderlichen Daten an die Ansicht. Die Parameter werden durch die Auswählen-Links auf der Seite bereitgestellt.
Tipp
Routendaten
Routendaten sind Daten, die der Modellbinder in einem URL-Segment gefunden hat, das in der Routingtabelle angegeben ist. Die Standardroute gibt beispielsweise die Segmente , action
und id
ancontroller
:
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
In der folgenden URL wird Instructor
die Standardroute als controller
, Index
als action
und 1 als zugeordnet id
. Dabei handelt es sich um Routendatenwerte.
http://localhost:1230/Instructor/Index/1?courseID=2021
"?courseID=2021" ist ein Abfragezeichenfolgenwert. Die Modellbindung funktioniert auch, wenn Sie den id
als Abfragezeichenfolgenwert übergeben:
http://localhost:1230/Instructor/Index?id=1&CourseID=2021
Die URLs werden von ActionLink
Anweisungen in der Razor-Ansicht erstellt. Im folgenden Code stimmt der id
Parameter mit der Standardroute überein, sodass id
den Routendaten hinzugefügt wird.
@Html.ActionLink("Select", "Index", new { id = item.PersonID })
Im folgenden Code courseID
stimmt nicht mit einem Parameter in der Standardroute überein, daher wird er als Abfragezeichenfolge hinzugefügt.
@Html.ActionLink("Select", "Index", new { courseID = item.CourseID })
Der Code erstellt zuerst eine Instanz des Ansichtsmodells und fügt die Dozentenliste ein. Der Code gibt eager loading 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 Courses, 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 "Eager Loading" nicht erforderlich, wird jedoch durchgeführt, 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, sodass eifriges Laden besser ist als verzögertes Laden nur, wenn die Seite häufiger mit einem ausgewählten Kurs als ohne angezeigt wird.
Wenn eine Dozenten-ID ausgewählt wurde, wird der ausgewählte Dozent aus der Liste der Dozenten 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.InstructorID == 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 Sammlung, wenn Sie wissen, dass die Sammlung nur ein Element enthält. Die Single
-Methode löst eine Ausnahme aus, wenn die an sie übergebene Auflistung leer ist oder 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 immer noch zu einer Ausnahme führen (von dem Versuch, eine Courses
Eigenschaft für einen null
Verweis zu finden), und die Ausnahmemeldung würde die Ursache des Problems weniger eindeutig angeben. Wenn Sie die Single
-Methode aufrufen, können Sie auch die Where
Bedingung übergeben, anstatt die Where
-Methode separat aufzurufen:
.Single(i => i.InstructorID == id.Value)
anstelle von:
.Where(I => i.InstructorID == 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 vorhandenen Code 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>
<tr>
<th></th>
<th>Last Name</th>
<th>First Name</th>
<th>Hire Date</th>
<th>Office</th>
</tr>
@foreach (var item in Model.Instructors)
{
string selectedRow = "";
if (item.InstructorID == ViewBag.InstructorID)
{
selectedRow = "selectedrow";
}
<tr class="@selectedRow" valign="top">
<td>
@Html.ActionLink("Select", "Index", new { id = item.InstructorID }) |
@Html.ActionLink("Edit", "Edit", new { id = item.InstructorID }) |
@Html.ActionLink("Details", "Details", new { id = item.InstructorID }) |
@Html.ActionLink("Delete", "Delete", new { id = item.InstructorID })
</td>
<td>
@item.LastName
</td>
<td>
@item.FirstMidName
</td>
<td>
@Html.DisplayFor(modelItem => item.HireDate)
</td>
<td>
@if (item.OfficeAssignment != null)
{
@item.OfficeAssignment.Location
}
</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.
Die Zeilenlinkspalten wurden nach links verschoben.
Die Spalte FullName wurde entfernt.
Eine Office-Spalte wurde hinzugefügt, die nur angezeigt wird
item.OfficeAssignment.Location
, wennitem.OfficeAssignment
nicht NULL ist. (Da dies eine 1:0-Beziehung oder eine Beziehung ist, 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 Dozenten dynamisch hinzugefügtclass="selectedrow"
wird. Dadurch wird eine Hintergrundfarbe für die ausgewählte Zeile mithilfe der CSS-Klasse festgelegt, die Sie zuvor erstellt haben. (Dasvalign
Attribut ist im folgenden Tutorial nützlich, wenn Sie der Tabelle eine Spalte mit mehreren Zeilen hinzufügen.)string selectedRow = ""; if (item.InstructorID == ViewBag.InstructorID) { selectedRow = "selectedrow"; } <tr class="@selectedRow" valign="top">
Direkt vor den anderen Links in jeder Zeile wurde eine neue
ActionLink
Bezeichnung mit der Bezeichnung Select hinzugefügt, wodurch die ausgewählte Dozenten-ID an dieIndex
-Methode gesendet wird.
Führen Sie die Anwendung aus, und wählen Sie die Registerkarte Dozenten aus. Auf der Seite werden die Location
-Eigenschaft verwandter OfficeAssignment
Entitäten und eine leere Tabellenzelle angezeigt, wenn keine verknüpfte 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 hervorgehobenen Code hinzu. Dadurch wird eine Liste von Kursen angezeigt, die sich auf einen Kursleiter beziehen, wenn ein Kursleiter ausgewählt wird.
<td>
@if (item.OfficeAssignment != null)
{
@item.OfficeAssignment.Location
}
</td>
</tr>
}
</table>
@if (Model.Courses != null)
{
<h3>Courses Taught by Selected Instructor</h3>
<table>
<tr>
<th></th>
<th>ID</th>
<th>Title</th>
<th>Department</th>
</tr>
@foreach (var item in Model.Courses)
{
string selectedRow = "";
if (item.CourseID == ViewBag.CourseID)
{
selectedRow = "selectedrow";
}
<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.
Hinweis
Die CSS-Datei wird von Browsern zwischengespeichert. Wenn die Änderungen beim Ausführen der Anwendung nicht angezeigt werden, führen Sie eine harte Aktualisierung durch (halten Sie die STRG-TASTE gedrückt, während Sie auf die Schaltfläche Aktualisieren klicken, oder drücken Sie STRG+F5).
Führen Sie die Seite aus, und wählen Sie einen Dozenten 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>
<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 Dozenten aus. Wählen Sie dann einen Kurs aus, um die Liste der registrierten Studenten und deren Noten einzusehen.
Hinzufügen von expliziten Ladevorgängen
Ö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;
}
Wenn Sie die Liste der Kursleiter abgerufen haben, haben Sie eager loading für die Courses
Navigationseigenschaft und für 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 Sammlung auf die Enrollments
Navigationseigenschaft zu. Da Sie kein eager loading für die Course.Enrollments
Navigationseigenschaft angegeben haben, werden die Daten aus dieser Eigenschaft auf der Seite angezeigt, da sie verzögert geladen werden.
Wenn Sie das verzögerte Laden deaktiviert haben, ohne den Code auf andere Weise zu ändern, wäre 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 eager loading oder explizit laden angeben. Sie haben bereits erfahren, 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.InstructorID == id.Value).Single().Courses;
}
if (courseID != null)
{
ViewBag.CourseID = courseID.Value;
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. Sie können die Seite Instructor Index jetzt ausführen, und Es wird kein Unterschied in der Anzeige auf der Seite angezeigt, obwohl Sie geändert haben, wie die Daten abgerufen werden.
Zusammenfassung
Sie haben jetzt alle drei Möglichkeiten (faul, eifrig und explizit) verwendet, um verwandte Daten in Navigationseigenschaften zu laden. Das nächste Tutorial zeigt die Aktualisierung verwandter Daten.
Links zu anderen Entity Framework-Ressourcen finden Sie im ASP.NET Data Access Content Map.