Freigeben über


Lernprogramm: Lesen verwandter Daten mit EF in einer ASP.NET MVC-App

Im vorherigen Lernprogramm haben Sie das Schuldatenmodell abgeschlossen. In diesem Lernprogramm lesen und anzeigen Sie verwandte Daten , d. h. Daten, die das Entity Framework in Navigationseigenschaften lädt.

Die folgenden Abbildungen zeigen die Seiten, mit den Sie arbeiten werden.

Screenshot der 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 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 für jedes Mal, wenn die zugehörigen Daten für die Entität abgerufen werden müssen. Die DbContext Klasse aktiviert standardmäßig das faule 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 das laden mit der Include Methode an.

    Eager_loading_example

  • Explizites Laden. Dies ähnelt dem faulen 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 Reference.Load-Methode für Eigenschaften aufrufen, die eine einzelne Entität enthalten. (Im folgenden Beispiel würden Sie Collection(x => x.Courses) Reference(x => x.Administrator)ersetzen, wenn Sie die Administratornavigationseigenschaft laden möchten.) In der Regel verwenden Sie explizites Laden nur, wenn Sie das Laden deaktiviert haben.

    Explicit_loading_example

Da sie die Eigenschaftswerte nicht sofort abrufen, werden faules 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 wir beispielsweise in den obigen Beispielen an, dass jede Abteilung zehn verwandte Kurse hat. Das eifrige Ladebeispiel würde nur zu einer einzigen Abfrage (Verknüpfung) und einem einzelnen Roundtrip zur Datenbank führen. Die faulen Lade- und expliziten Ladebeispiele 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.

Andererseits ist in manchen Szenarien das faule Laden effizienter. Das laden kann dazu führen, dass eine sehr komplexe Verknüpfung generiert wird, 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, ist das Laden möglicherweise besser geeignet, da das Laden mit Eifer mehr Daten abruft, 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.

Lazy loading can mask code that causes performance problems. Beispielsweise kann Code, der nicht das explizite Laden angibt, sondern ein hohes Volumen von Entitäten verarbeitet und mehrere Navigationseigenschaften in jeder Iteration verwendet, sehr ineffizient sein (aufgrund vieler Roundtrips zur Datenbank). Eine Anwendung, die bei der Entwicklung mit einem lokalen SQL-Server gut funktioniert, hat möglicherweise Leistungsprobleme, wenn sie aufgrund der erhöhten Latenz und des faulen Ladens zu Azure SQL-Datenbank verschoben werden. Das Profilieren der Datenbankabfragen mit einer realistischen Testlast hilft Ihnen, zu ermitteln, ob das Laden von Faulen geeignet ist. Weitere Informationen finden Sie unter Demystifying Entity Framework Strategies: Loading Related Data and Using the Entity Framework to Reduce Network Latency to SQL Azure.For more information see Demystifying Entity Framework Strategies: Loading Related Data and Using the Entity Framework to Reduce Network Latency to SQL Azure.

Deaktivieren des faulen Ladens vor der Serialisierung

Wenn Sie während der Serialisierung faules Laden aktiviert lassen, können Sie wesentlich mehr Daten abfragen als beabsichtigt. Serialisierung funktioniert in der Regel, indem auf jede Eigenschaft in einer Instanz eines Typs zugegriffen wird. Der Eigenschaftenzugriff löst das faule 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 noch lazyre Lade- und Serialisierung verursacht. Um diese Ablaufzeit-Kettenreaktion zu verhindern, deaktivieren Sie das Laden, bevor Sie eine Entität serialisieren.

Serialisierung kann auch durch die proxyklassen kompliziert sein, die das Entity Framework verwendet, wie im Lernprogramm "Erweiterte 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 Lernprogramm "Verwenden der Web-API mit Entity Framework " gezeigt.

Wenn Sie DTOs nicht verwenden, können Sie das Laden deaktivieren und Proxyprobleme vermeiden, indem Sie die Proxyerstellung deaktivieren.

Hier sind einige weitere Möglichkeiten zum Deaktivieren des faulen Ladens:

  • Für bestimmte Navigationseigenschaften müssen Sie das virtual Schlüsselwort weglassen, wenn Sie die Eigenschaft deklarieren.

  • Fügen Sie für alle Navigationseigenschaften den LazyLoadingEnabled falsefolgenden 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 Eigenschaft aus der Name 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, indem Sie die gleichen Optionen für den MVC 5-Controller mit Ansichten verwenden, indem Sie das Entity Framework-Gerüst verwenden, das Sie zuvor für den Student Controller ausgeführt haben:

Einstellung Wert
Modellklasse Wählen Sie "Kurs" (ContosoUniversity.Models) aus.
Datenkontextklasse Wählen Sie SchoolContext (ContosoUniversity.DAL) aus.
Controllername Geben Sie "CourseController" ein. Wieder, nicht CoursesController mit einem s. Wenn Sie "Kurs" (ContosoUniversity.Models) ausgewählt haben, wurde der Namewert des Controllers automatisch ausgefüllt. Sie müssen den Wert ändern.

Behalten Sie die anderen Standardwerte bei, und fügen Sie den Controller hinzu.

Öffnen Sie Controller\CourseController.cs , und sehen Sie sich die Index Methode an:

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. Standardmäßig werden Primärschlüssel 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 auf die rechte Seite verschoben und die Überschrift geändert. Das Gerüst hat richtig ausgewählt, dass die Eigenschaft aus der Name Department Entität angezeigt wird, aber hier auf der Seite "Kurs" sollte die Spaltenüberschrift "Abteilung" statt "Name" lauten.

Beachten Sie, dass für die Abteilungsspalte der Gerüstcode die Name Eigenschaft der Department Entität anzeigt, die in die Department Navigationseigenschaft geladen wird:

<td>
    @Html.DisplayFor(modelItem => item.Department.Name)
</td>

Führen Sie die Seite aus (wählen Sie die Registerkarte "Kurse " auf der Startseite der Contoso University aus), um die Liste mit 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 "Kursleiter" 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 deren zugehörige Student Entitäten hinzu. (Das explizite Laden ist nicht erforderlich, da das faule Laden aktiviert ist. Dies zeigt jedoch, wie das explizite Laden erfolgt.)

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 "ViewModels" InstructorIndexData.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-/Schreibzugriff:

Einstellung Wert
Modellklasse Wählen Sie "Instructor" (ContosoUniversity.Models) aus.
Datenkontextklasse Wählen Sie SchoolContext (ContosoUniversity.DAL) aus.
Controllername Geben Sie "InstructorController" ein. Wieder, nicht InstructorsController mit einem s. Wenn Sie "Kurs" (ContosoUniversity.Models) ausgewählt haben, wurde der Namewert des Controllers automatisch ausgefüllt. Sie müssen den Wert ändern.

Behalten Sie die anderen Standardwerte bei, und fügen Sie den Controller hinzu.

Öffnen Sie Controller\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 im Ansichtsmodell einzufügen:

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), der die ID-Werte des ausgewählten Kursleiters und des ausgewählten Kurses bereitstellt, 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 den eifrigen Ladevorgang für die Instructor.OfficeAssignment und die Instructor.Courses Navigationseigenschaft an.

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 kurs, der geladen wird, wird es für die Course.Department Navigationseigenschaft eifrig geladen.

.Include(i => i.Courses.Select(c => c.Department))

Wie bereits erwähnt, ist das begierige Laden nicht erforderlich, aber zur Verbesserung der Leistung. 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 das laden besser als faules Laden nur, 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 nur zu einer einzelnen Instructor Entität, die 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, die einen Standardwert (null in diesem Fall) zurückgibt, wenn die Auflistung leer ist. In diesem Fall würde dies jedoch weiterhin zu einer Ausnahme führen (aus dem Versuch, eine Courses Eigenschaft in einem null Verweis zu finden), und die Ausnahmemeldung würde weniger deutlich die Ursache des Problems angeben. Wenn Sie die Single Methode aufrufen, können Sie die Bedingung auch übergeben Where , 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 Enrollments Ansichtsmodells mit den Enrollment Entitäten aus der 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.

  • Es wurde eine Office-Spalte hinzugefügt, die nur angezeigt wird item.OfficeAssignment.Location , wenn item.OfficeAssignment sie nicht null ist. (Da es sich hierbei um eine 1:0-oder-1-Beziehung handelt, gibt es möglicherweise keine zugehörige OfficeAssignment Entität.)

    <td> 
        @if (item.OfficeAssignment != null) 
        { 
            @item.OfficeAssignment.Location  
        } 
    </td>
    
  • Code hinzugefügt, der tr dem Element des ausgewählten Kursleiters dynamisch hinzugefügt class="success" wird. Hiermit wird eine Hintergrundfarbe mit einer Bootstrapklasse für die ausgewählte Zeile hinzugefügt.

    string selectedRow = ""; 
    if (item.InstructorID == ViewBag.InstructorID) 
    { 
        selectedRow = "success"; 
    } 
    <tr class="@selectedRow" valign="top">
    
  • Es wurde unmittelbar vor den anderen Links in jeder Zeile eine neue ActionLink bezeichnung " Select " 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 "Kursleiter" aus. Auf der Seite werden die Location Eigenschaft verwandter OfficeAssignment Entitäten und eine leere Tabellenzelle angezeigt, 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 schauen 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 den eifrigen Ladevorgang 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 kein begieriges Laden für die Course.Enrollments Navigationseigenschaft angegeben haben, werden die Daten aus dieser Eigenschaft als Ergebnis des ladens faulen Ladens auf der Seite angezeigt.

Wenn Sie das 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 das gewünschte Laden oder das explizite Laden angeben. Sie haben bereits gesehen, wie Sie das Laden begierig machen. 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 ist 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 die Navigationseigenschaft dieses Kurses Enrollments explizit:

db.Entry(selectedCourse).Collection(x => x.Enrollments).Load();

Anschließend wird explizit die zugehörige Student Entität der einzelnen Enrollment Entitäten 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 die Seite "Kursleiterindex" jetzt 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.