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.

Screenshot: Seite

Instructors_index_page_with_instructor_and_course_selected

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

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.

    Lazy_loading_example

  • 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.

    Eager_loading_example

  • 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 durch Reference(x => x.Administrator).) In der Regel verwenden Sie explizites Laden nur, wenn Sie verzögertes Laden deaktiviert haben.

    Explicit_loading_example

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 falsefestLazyLoadingEnabled, 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 der Department 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. Die Instructor- und OfficeAssignment-Entitäten stehen in einer 1:0..1-Beziehung zueinander. Für die OfficeAssignment-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. Die Instructor- und Course-Entitäten stehen in einer m:n-Beziehung zueinander. Für die Course-Entitäten und die zugehörigen Department-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. Die Course- und Enrollment-Entitäten stehen in einer 1:n-Beziehung zueinander. Sie fügen explizites Laden für Enrollment Entitäten und die zugehörigen Student 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 , wenn item.OfficeAssignment nicht NULL ist. (Da es sich hierbei um eine 1:1-Beziehung handelt, gibt es möglicherweise keine verwandte OfficeAssignment Entität.)

    <td> 
        @if (item.OfficeAssignment != null) 
        { 
            @item.OfficeAssignment.Location  
        } 
    </td>
    
  • Code hinzugefügt, der dem tr Element des ausgewählten Kursleiters dynamisch hinzugefügt class="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 die Index -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.