Kurz: Čtení souvisejících dat – ASP.NET MVC pomocí EF Core

V předchozím kurzu jste dokončili datový model School. V tomto kurzu si přečtete a zobrazíte související data – to znamená data, která Entity Framework načte do navigačních vlastností.

Následující ilustrace znázorňují stránky, se kterými budete pracovat.

Courses Index page

Instructors Index page

V tomto kurzu se naučíte:

  • Naučte se načítat související data.
  • Vytvoření stránky Kurzy
  • Vytvoření stránky instruktorů
  • Informace o explicitním načítání

Požadavky

Software ORM (Object-Relational Mapping), jako je Entity Framework, může načíst související data do navigačních vlastností entity:

  • Načítání dychtivých dat: Při čtení entity se spolu s ní načtou související data. Výsledkem je obvykle jeden dotaz spojení, který načte všechna potřebná data. Zadáním dychtivého načítání do Entity Framework Core pomocí metod Include a ThenInclude metod.

    Eager loading example

    Některá data můžete načíst v samostatnýchdotazch Ef tedy automaticky přidá samostatně načtené entity, do kterých patří do navigačních vlastností dříve načtených entit. Pro dotaz, který načte související data, můžete použít Load metodu místo metody, která vrací seznam nebo objekt, například ToList nebo Single.

    Separate queries example

  • Explicitní načtení: Při prvním čtení entity se související data nenačtou. Napíšete kód, který načte související data, pokud je to potřeba. Stejně jako v případě dychtivého načítání samostatnými dotazy má explicitní načtení za následek více dotazů odesílaných do databáze. Rozdíl je v tom, že při explicitním načtení určuje kód vlastnosti navigace, které se mají načíst. V Entity Framework Core 1.1 můžete použít metodu Load k explicitnímu načítání. Příklad:

    Explicit loading example

  • Opožděné načítání: Při prvním čtení entity se související data nenačtou. Při prvním pokusu o přístup k navigační vlastnosti se však automaticky načtou data potřebná pro tuto navigační vlastnost. Dotaz se odešle do databáze pokaždé, když se pokusíte získat data z navigační vlastnosti poprvé. Entity Framework Core 1.0 nepodporuje opožděné načítání.

Důležité informace o výkonu

Pokud víte, že potřebujete související data pro každou načtenou entitu, načítání dychtivosti často nabízí nejlepší výkon, protože jeden dotaz odeslaný do databáze je obvykle efektivnější než samostatné dotazy pro každou načtenou entitu. Předpokládejme například, že každé oddělení má deset souvisejících kurzů. Dychtivá načtení všech souvisejících dat by vedlo k jedinému dotazu (spojení) a jediné odezvě databáze. Samostatný dotaz pro kurzy pro každé oddělení by vedlo k jedenácti odezvě do databáze. Dodatečné odezvy databáze jsou zvláště škodlivé pro výkon, pokud je latence vysoká.

Na druhou stranu v některých scénářích jsou samostatné dotazy efektivnější. Dychtivá načítání všech souvisejících dat v jednom dotazu může způsobit generování velmi složitého spojení, které SQL Server nemůže efektivně zpracovat. Nebo pokud potřebujete získat přístup k navigačním vlastnostem entity pouze pro podmnožinu sady entit, které zpracováváte, můžou samostatné dotazy fungovat lépe, protože dychtivé načítání všeho předem by načítalo více dat, než potřebujete. Pokud je výkon kritický, je nejlepší otestovat výkon oběma způsoby, aby byla nejlepší volbou.

Vytvoření stránky Kurzy

Entita Course obsahuje navigační vlastnost, která obsahuje entitu Department oddělení, ke kterému je kurz přiřazen. Pokud chcete zobrazit název přiřazeného oddělení v seznamu kurzů, musíte vlastnost získat Name z Department entity, která je v Course.Department navigační vlastnosti.

Vytvořte kontroler pojmenovaný CoursesController pro Course typ entity pomocí stejných možností pro kontroler MVC se zobrazeními pomocí nástroje Entity Framework scaffolder, který jste provedli dříve pro danou entitu StudentsController, jak je znázorněno na následujícím obrázku:

Add Courses controller

Otevřete CoursesController.cs a prozkoumejte metodu Index . Automatické generování uživatelského rozhraní pomocí metody určilo dychtivé načítání pro Department navigační vlastnost Include .

Nahraďte metodu Index následujícím kódem, který používá vhodnější název pro IQueryable entity kurzu (courses místo schoolContext):

public async Task<IActionResult> Index()
{
    var courses = _context.Courses
        .Include(c => c.Department)
        .AsNoTracking();
    return View(await courses.ToListAsync());
}

Otevřete Views/Courses/Index.cshtml a nahraďte kód šablony následujícím kódem. Změny jsou zvýrazněné:

@model IEnumerable<ContosoUniversity.Models.Course>

@{
    ViewData["Title"] = "Courses";
}

<h2>Courses</h2>

<p>
    <a asp-action="Create">Create New</a>
</p>
<table class="table">
    <thead>
        <tr>
            <th>
                @Html.DisplayNameFor(model => model.CourseID)
            </th>
            <th>
                @Html.DisplayNameFor(model => model.Title)
            </th>
            <th>
                @Html.DisplayNameFor(model => model.Credits)
            </th>
            <th>
                @Html.DisplayNameFor(model => model.Department)
            </th>
            <th></th>
        </tr>
    </thead>
    <tbody>
        @foreach (var item in Model)
        {
            <tr>
                <td>
                    @Html.DisplayFor(modelItem => item.CourseID)
                </td>
                <td>
                    @Html.DisplayFor(modelItem => item.Title)
                </td>
                <td>
                    @Html.DisplayFor(modelItem => item.Credits)
                </td>
                <td>
                    @Html.DisplayFor(modelItem => item.Department.Name)
                </td>
                <td>
                    <a asp-action="Edit" asp-route-id="@item.CourseID">Edit</a> |
                    <a asp-action="Details" asp-route-id="@item.CourseID">Details</a> |
                    <a asp-action="Delete" asp-route-id="@item.CourseID">Delete</a>
                </td>
            </tr>
        }
    </tbody>
</table>

Vygenerovaný kód jste provedli následující změny:

  • Změnili jsme nadpis z indexu na Kurzy.

  • Přidali jsme sloupec Číslo , který zobrazuje CourseID hodnotu vlastnosti. Ve výchozím nastavení se primární klíče nevygenerují, protože obvykle nejsou pro koncové uživatele smysluplné. V tomto případě je ale primární klíč smysluplný a chcete ho zobrazit.

  • Změnili jsme sloupec Oddělení tak, aby zobrazoval název oddělení. Kód zobrazí Name vlastnost Department entity, která je načtena do Department navigační vlastnosti:

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

Spusťte aplikaci a výběrem karty Kurzy zobrazte seznam s názvy oddělení.

Courses Index page

Vytvoření stránky instruktorů

V této části vytvoříte kontroler a zobrazíte entitu Instructor , abyste zobrazili stránku instruktorů:

Instructors Index page

Tato stránka čte a zobrazuje související data následujícími způsoby:

  • Seznam instruktorů zobrazuje související data z OfficeAssignment dané entity. OfficeAssignment Entity Instructor jsou v relaci 1:0 nebo 1. Pro entity použijete dychtivé načítání OfficeAssignment . Jak bylo vysvětleno dříve, načítání dychtivosti je obvykle efektivnější, když potřebujete související data pro všechny načtené řádky primární tabulky. V takovém případě chcete zobrazit zadání kanceláře pro všechny zobrazené instruktory.

  • Když uživatel vybere instruktora, zobrazí se související Course entity. Entity Instructor a Course entity jsou v relaci M:N. Pro entity a související Department entity použijete dychtivé načítáníCourse. V takovém případě můžou být samostatné dotazy efektivnější, protože potřebujete kurzy jenom pro vybraného instruktora. Tento příklad však ukazuje, jak používat dychtivé načítání vlastností navigace v rámci entit, které jsou samy ve vlastnostech navigace.

  • Když uživatel vybere kurz, zobrazí se související data ze Enrollments sady entit. Entity Course a Enrollment entity jsou v relaci 1:N. Použijete samostatné dotazy pro Enrollment entity a jejich související Student entity.

Vytvoření modelu zobrazení pro zobrazení indexu instruktora

Na stránce Instruktori se zobrazují data ze tří různých tabulek. Proto vytvoříte model zobrazení, který obsahuje tři vlastnosti, z nichž každá obsahuje data pro jednu z tabulek.

Ve složce SchoolViewModels vytvořte InstructorIndexData.cs a nahraďte existující kód následujícím kódem:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace ContosoUniversity.Models.SchoolViewModels
{
    public class InstructorIndexData
    {
        public IEnumerable<Instructor> Instructors { get; set; }
        public IEnumerable<Course> Courses { get; set; }
        public IEnumerable<Enrollment> Enrollments { get; set; }
    }
}

Vytvoření kontroleru a zobrazení instruktora

Vytvořte kontroler instruktorů s akcemi EF pro čtení a zápis, jak je znázorněno na následujícím obrázku:

Add Instructors controller

Otevřete InstructorsController.cs a přidejte příkaz using pro obor názvů ViewModels:

using ContosoUniversity.Models.SchoolViewModels;

Nahraďte metodu Index následujícím kódem, který docítí načítání souvisejících dat a vloží je do modelu zobrazení.

public async Task<IActionResult> Index(int? id, int? courseID)
{
    var viewModel = new InstructorIndexData();
    viewModel.Instructors = await _context.Instructors
          .Include(i => i.OfficeAssignment)
          .Include(i => i.CourseAssignments)
            .ThenInclude(i => i.Course)
                .ThenInclude(i => i.Enrollments)
                    .ThenInclude(i => i.Student)
          .Include(i => i.CourseAssignments)
            .ThenInclude(i => i.Course)
                .ThenInclude(i => i.Department)
          .AsNoTracking()
          .OrderBy(i => i.LastName)
          .ToListAsync();
    
    if (id != null)
    {
        ViewData["InstructorID"] = id.Value;
        Instructor instructor = viewModel.Instructors.Where(
            i => i.ID == id.Value).Single();
        viewModel.Courses = instructor.CourseAssignments.Select(s => s.Course);
    }

    if (courseID != null)
    {
        ViewData["CourseID"] = courseID.Value;
        viewModel.Enrollments = viewModel.Courses.Where(
            x => x.CourseID == courseID).Single().Enrollments;
    }

    return View(viewModel);
}

Metoda přijímá volitelná data směrování (id) a parametr řetězce dotazu (courseID), který poskytuje hodnoty ID vybraného instruktora a vybraného kurzu. Parametry poskytují hypertextové odkazy na stránce.

Kód začíná vytvořením instance modelu zobrazení a jeho vložením do seznamu instruktorů. Kód určuje dychtivé načítání pro Instructor.OfficeAssignment vlastnosti navigace a Instructor.CourseAssignments vlastnosti navigace. V rámci CourseAssignments této vlastnosti se vlastnost Course načte a v rámci této Enrollments vlastnosti se načtou a Department v rámci každé Enrollment entity Student se vlastnost načte.

viewModel.Instructors = await _context.Instructors
      .Include(i => i.OfficeAssignment)
      .Include(i => i.CourseAssignments)
        .ThenInclude(i => i.Course)
            .ThenInclude(i => i.Enrollments)
                .ThenInclude(i => i.Student)
      .Include(i => i.CourseAssignments)
        .ThenInclude(i => i.Course)
            .ThenInclude(i => i.Department)
      .AsNoTracking()
      .OrderBy(i => i.LastName)
      .ToListAsync();

Vzhledem k tomu, že zobrazení vždy vyžaduje entitu OfficeAssignment , je efektivnější ji načíst ve stejném dotazu. Entity kurzu se vyžadují, když je na webové stránce vybrán instruktor, takže jeden dotaz je lepší než více dotazů, pouze pokud se stránka zobrazuje častěji s vybraným kurzem než bez.

Kód se CourseAssignments opakuje a Course protože potřebujete dvě vlastnosti z Course. První řetězec ThenInclude volání získá CourseAssignment.Course, Course.Enrollmentsa Enrollment.Student.

Další informace o zahrnutí více úrovní souvisejících dat najdete tady.

viewModel.Instructors = await _context.Instructors
      .Include(i => i.OfficeAssignment)
      .Include(i => i.CourseAssignments)
        .ThenInclude(i => i.Course)
            .ThenInclude(i => i.Enrollments)
                .ThenInclude(i => i.Student)
      .Include(i => i.CourseAssignments)
        .ThenInclude(i => i.Course)
            .ThenInclude(i => i.Department)
      .AsNoTracking()
      .OrderBy(i => i.LastName)
      .ToListAsync();

V tomto okamžiku v kódu by další ThenInclude byl pro navigační vlastnosti Student, které nepotřebujete. Ale volání Include začíná s vlastnostmi Instructor , takže musíte znovu procházet řetěz, tentokrát zadat Course.Department místo Course.Enrollments.

viewModel.Instructors = await _context.Instructors
      .Include(i => i.OfficeAssignment)
      .Include(i => i.CourseAssignments)
        .ThenInclude(i => i.Course)
            .ThenInclude(i => i.Enrollments)
                .ThenInclude(i => i.Student)
      .Include(i => i.CourseAssignments)
        .ThenInclude(i => i.Course)
            .ThenInclude(i => i.Department)
      .AsNoTracking()
      .OrderBy(i => i.LastName)
      .ToListAsync();

Následující kód se spustí, když byl vybrán instruktor. Vybraný instruktor se načte ze seznamu instruktorů v modelu zobrazení. Vlastnost modelu Courses zobrazení se pak načte s Course entitami z navigační vlastnosti daného instruktora CourseAssignments .

if (id != null)
{
    ViewData["InstructorID"] = id.Value;
    Instructor instructor = viewModel.Instructors.Where(
        i => i.ID == id.Value).Single();
    viewModel.Courses = instructor.CourseAssignments.Select(s => s.Course);
}

Metoda Where vrátí kolekci, ale v tomto případě kritéria předaná této metodě způsobí vrácení pouze jedné entity instruktora. Metoda Single převede kolekci na jednu Instructor entitu, která poskytuje přístup k vlastnosti dané entity CourseAssignments . Vlastnost CourseAssignments obsahuje CourseAssignment entity, ze kterých chcete pouze související Course entity.

Metodu Single v kolekci použijete, když víte, že kolekce bude obsahovat pouze jednu položku. Metoda Single vyvolá výjimku, pokud je kolekce předána do prázdné nebo pokud existuje více než jedna položka. Alternativou je SingleOrDefault, která vrátí výchozí hodnotu (v tomto případě null), pokud je kolekce prázdná. V tomto případě by však stále došlo k výjimce (z pokusu o nalezení Courses vlastnosti u odkazu s hodnotou null) a zpráva o výjimce by méně jasně označovala příčinu problému. Při volání Single metody můžete také předat podmínku Where namísto samostatného volání Where metody:

.Single(i => i.ID == id.Value)

Místo:

.Where(i => i.ID == id.Value).Single()

Pokud jste vybrali kurz, vybraný kurz se načte ze seznamu kurzů v modelu zobrazení. Vlastnost modelu Enrollments zobrazení se pak načte s entitami registrace z navigační Enrollments vlastnosti daného kurzu.

if (courseID != null)
{
    ViewData["CourseID"] = courseID.Value;
    viewModel.Enrollments = viewModel.Courses.Where(
        x => x.CourseID == courseID).Single().Enrollments;
}

Sledování vs. bez sledování

Dotazy bez sledování jsou užitečné, když se výsledky používají ve scénáři jen pro čtení. Obvykle jsou rychlejší, protože není potřeba nastavovat informace o sledování změn. Pokud entity načtené z databáze nemusí být aktualizovány, pak dotaz bez sledování bude pravděpodobně fungovat lépe než sledovací dotaz.

V některých případech je sledovací dotaz efektivnější než dotaz bez sledování. Další informace naleznete v tématu Sledování vs. Dotazy bez sledování.

Úprava zobrazení indexu instruktora

Nahraďte Views/Instructors/Index.cshtmlkód šablony následujícím kódem. Změny jsou zvýrazněné.

@model ContosoUniversity.Models.SchoolViewModels.InstructorIndexData

@{
    ViewData["Title"] = "Instructors";
}

<h2>Instructors</h2>

<p>
    <a asp-action="Create">Create New</a>
</p>
<table class="table">
    <thead>
        <tr>
            <th>Last Name</th>
            <th>First Name</th>
            <th>Hire Date</th>
            <th>Office</th>
            <th>Courses</th>
            <th></th>
        </tr>
    </thead>
    <tbody>
        @foreach (var item in Model.Instructors)
        {
            string selectedRow = "";
            if (item.ID == (int?)ViewData["InstructorID"])
            {
                selectedRow = "table-success";
            }
            <tr class="@selectedRow">
                <td>
                    @Html.DisplayFor(modelItem => item.LastName)
                </td>
                <td>
                    @Html.DisplayFor(modelItem => item.FirstMidName)
                </td>
                <td>
                    @Html.DisplayFor(modelItem => item.HireDate)
                </td>
                <td>
                    @if (item.OfficeAssignment != null)
                    {
                        @item.OfficeAssignment.Location
                    }
                </td>
                <td>
                    @foreach (var course in item.CourseAssignments)
                    {
                        @course.Course.CourseID @course.Course.Title <br />
                    }
                </td>
                <td>
                    <a asp-action="Index" asp-route-id="@item.ID">Select</a> |
                    <a asp-action="Edit" asp-route-id="@item.ID">Edit</a> |
                    <a asp-action="Details" asp-route-id="@item.ID">Details</a> |
                    <a asp-action="Delete" asp-route-id="@item.ID">Delete</a>
                </td>
            </tr>
           }
    </tbody>
</table>
@model ContosoUniversity.Models.SchoolViewModels.InstructorIndexData

@{
    ViewData["Title"] = "Instructors";
}

<h2>Instructors</h2>

<p>
    <a asp-action="Create">Create New</a>
</p>
<table class="table">
    <thead>
        <tr>
            <th>Last Name</th>
            <th>First Name</th>
            <th>Hire Date</th>
            <th>Office</th>
            <th>Courses</th>
            <th></th>
        </tr>
    </thead>
    <tbody>
        @foreach (var item in Model.Instructors)
        {
            string selectedRow = "";
            if (item.ID == (int?)ViewData["InstructorID"])
            {
                selectedRow = "success";
            }
            <tr class="@selectedRow">
                <td>
                    @Html.DisplayFor(modelItem => item.LastName)
                </td>
                <td>
                    @Html.DisplayFor(modelItem => item.FirstMidName)
                </td>
                <td>
                    @Html.DisplayFor(modelItem => item.HireDate)
                </td>
                <td>
                    @if (item.OfficeAssignment != null)
                    {
                        @item.OfficeAssignment.Location
                    }
                </td>
                <td>
                    @foreach (var course in item.CourseAssignments)
                    {
                        @course.Course.CourseID @course.Course.Title <br />
                    }
                </td>
                <td>
                    <a asp-action="Index" asp-route-id="@item.ID">Select</a> |
                    <a asp-action="Edit" asp-route-id="@item.ID">Edit</a> |
                    <a asp-action="Details" asp-route-id="@item.ID">Details</a> |
                    <a asp-action="Delete" asp-route-id="@item.ID">Delete</a>
                </td>
            </tr>
           }
    </tbody>
</table>

V existujícím kódu jste provedli následující změny:

  • Změna třídy modelu na InstructorIndexData.

  • Změnili jsme název stránky z indexu na instruktory.

  • Přidali jsme sloupec Office , který se zobrazí item.OfficeAssignment.Location jenom v případě item.OfficeAssignment , že nemá hodnotu null. (Vzhledem k tomu, že se jedná o relaci 1:0 nebo 1, nemusí existovat související entita OfficeAssignment.)

    @if (item.OfficeAssignment != null)
    {
        @item.OfficeAssignment.Location
    }
    
  • Přidali jsme sloupec Kurzy , který zobrazuje kurzy vyučované jednotlivými instruktory. Další informace najdete v části Razor Explicitní přechod řádku článku syntaxe.

  • Přidání kódu, který podmíněně přidá třídu CSS bootstrap do tr prvku vybraného instruktora. Tato třída nastaví barvu pozadí pro vybraný řádek.

  • Přidali jsme nový hypertextový odkaz s popiskem Vybrat bezprostředně před ostatní odkazy v každém řádku, což způsobí odeslání ID vybraného instruktora do Index metody.

    <a asp-action="Index" asp-route-id="@item.ID">Select</a> |
    

Spusťte aplikaci a vyberte kartu Instruktori . Na stránce se zobrazí vlastnost Umístění souvisejících entit OfficeAssignment a prázdná buňka tabulky, pokud neexistuje žádná související entita OfficeAssignment.

Instructors Index page nothing selected

Views/Instructors/Index.cshtml Do souboru za konečný prvek tabulky (na konci souboru) přidejte následující kód. Tento kód zobrazí seznam kurzů souvisejících s instruktorem, když je vybrán instruktor.


@if (Model.Courses != null)
{
    <h3>Courses Taught by Selected Instructor</h3>
    <table class="table">
        <tr>
            <th></th>
            <th>Number</th>
            <th>Title</th>
            <th>Department</th>
        </tr>

        @foreach (var item in Model.Courses)
        {
            string selectedRow = "";
            if (item.CourseID == (int?)ViewData["CourseID"])
            {
                selectedRow = "success";
            }
            <tr class="@selectedRow">
                <td>
                    @Html.ActionLink("Select", "Index", new { courseID = item.CourseID })
                </td>
                <td>
                    @item.CourseID
                </td>
                <td>
                    @item.Title
                </td>
                <td>
                    @item.Department.Name
                </td>
            </tr>
        }

    </table>
}

Tento kód přečte Courses vlastnost modelu zobrazení, aby se zobrazil seznam kurzů. Poskytuje také hypertextový odkaz Select , který odešle ID vybraného kurzu metodě Index akce.

Aktualizujte stránku a vyberte instruktora. Teď uvidíte mřížku, která zobrazuje kurzy přiřazené vybranému instruktorovi a pro každý kurz uvidíte název přiřazeného oddělení.

Instructors Index page instructor selected

Za blok kódu, který jste právě přidali, přidejte následující kód. Zobrazí se seznam studentů, kteří jsou zaregistrovaní v kurzu při výběru tohoto kurzu.

@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>
}

Tento kód přečte Enrollments vlastnost modelu zobrazení, aby se zobrazil seznam studentů zaregistrovaných v kurzu.

Aktualizujte stránku znovu a vyberte instruktora. Pak vyberte kurz, abyste viděli seznam zaregistrovaných studentů a jejich známek.

Instructors Index page instructor and course selected

Informace o explicitním načítání

Po načtení seznamu instruktorů jste zadali dychtivé InstructorsController.csnačítání pro CourseAssignments navigační vlastnost.

Předpokládejme, že jste očekávali, že uživatelé budou chtít jenom zřídka vidět registrace ve vybraném instruktoru a kurzu. V takovém případě můžete chtít načíst data registrace jenom v případě, že je požadována. Pokud chcete vidět příklad, jak provést explicitní načítání, nahraďte Index metodu následujícím kódem, který odebere dychtivé načítání Enrollments a načte danou vlastnost explicitně. Změny kódu jsou zvýrazněné.

public async Task<IActionResult> Index(int? id, int? courseID)
{
    var viewModel = new InstructorIndexData();
    viewModel.Instructors = await _context.Instructors
          .Include(i => i.OfficeAssignment)
          .Include(i => i.CourseAssignments)
            .ThenInclude(i => i.Course)
                .ThenInclude(i => i.Department)
          .OrderBy(i => i.LastName)
          .ToListAsync();

    if (id != null)
    {
        ViewData["InstructorID"] = id.Value;
        Instructor instructor = viewModel.Instructors.Where(
            i => i.ID == id.Value).Single();
        viewModel.Courses = instructor.CourseAssignments.Select(s => s.Course);
    }

    if (courseID != null)
    {
        ViewData["CourseID"] = courseID.Value;
        var selectedCourse = viewModel.Courses.Where(x => x.CourseID == courseID).Single();
        await _context.Entry(selectedCourse).Collection(x => x.Enrollments).LoadAsync();
        foreach (Enrollment enrollment in selectedCourse.Enrollments)
        {
            await _context.Entry(enrollment).Reference(x => x.Student).LoadAsync();
        }
        viewModel.Enrollments = selectedCourse.Enrollments;
    }

    return View(viewModel);
}

Nový kód zahodí ThenInclude volání metody pro data registrace z kódu, který načítá entity instruktora. Také klesá AsNoTracking. Pokud je vybrán instruktor a kurz, zvýrazněný kód načte Enrollment entity pro vybraný kurz a Student entity pro každý Enrollmentz nich .

Spusťte aplikaci, přejděte na stránku Index instruktorů a uvidíte žádný rozdíl v tom, co se na stránce zobrazuje, i když jste změnili způsob načtení dat.

Získání kódu

Stáhněte nebo zobrazte dokončenou aplikaci.

Další kroky

V tomto kurzu se naučíte:

  • Naučili jste se načíst související data.
  • Vytvoření stránky Kurzy
  • Vytvoření stránky instruktorů
  • Dozvěděli jste se o explicitním načítání

V dalším kurzu se dozvíte, jak aktualizovat související data.