Sdílet prostřednictvím


Čtení souvisejících dat pomocí Entity Frameworku v aplikaci ASP.NET MVC (5 z 10)

Tom Dykstra

Ukázková webová aplikace Contoso University ukazuje, jak vytvářet aplikace ASP.NET MVC 4 pomocí entity Framework 5 Code First a sady Visual Studio 2012. Informace o sérii kurzů najdete v prvním kurzu v této sérii.

Poznámka

Pokud narazíte na problém, který nemůžete vyřešit, stáhněte si dokončenou kapitolu a zkuste problém reprodukovat. Obecně můžete najít řešení problému porovnáním kódu s dokončeným kódem. Informace o některých běžných chybách a jejich řešení najdete v tématu Chyby a alternativní řešení.

V předchozím kurzu jste dokončili školní datový model. V tomto kurzu budete číst a zobrazovat 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.

Snímek obrazovky znázorňující indexovou stránku Contoso University Courses

Snímek obrazovky zobrazující stránku s indexem instruktora contoso university s instruktorem a jedním z vybraných kurzů

Existuje několik způsobů, jak může Entity Framework načíst související data do navigačních vlastností entity:

  • 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. Výsledkem je několik dotazů odeslaných do databáze – jeden pro samotnou entitu a druhý pokaždé, když se musí načíst související data entity.

    Lazy_loading_example

  • Dychtivé načítání. Když se entita načte, načtou se spolu s ní i související data. Výsledkem je obvykle jeden dotaz spojení, který načte všechna potřebná data. K určení dychtivého načítání použijete metodu Include .

    Eager_loading_example

  • Explicitní načítání To se podobá opožděné načítání, s výjimkou toho, že explicitně načtete související data v kódu; nedojde k tomu automaticky při přístupu k vlastnosti navigace. Související data načtete ručně tak, že získáte položku správce stavu objektu pro entitu a zavoláte metodu Collection.Load pro kolekce nebo metodu Reference.Load pro vlastnosti, které obsahují jednu entitu. (Pokud byste v následujícím příkladu chtěli načíst navigační vlastnost Správce, nahradili Collection(x => x.Courses)Reference(x => x.Administrator)byste za .)

    Explicit_loading_example

Vzhledem k tomu, že nenačítají hodnoty vlastností okamžitě, líné načítání i explicitní načítání se také označuje jako odložené načítání.

Obecně platí, že pokud víte, že potřebujete související data pro každou načtenou entitu, nabízí dychtivé načítání nejlepší výkon, protože jeden dotaz odeslaný do databáze je obvykle efektivnější než samostatné dotazy pro každou načtenou entitu. Ve výše uvedených příkladech předpokládejme, že každé oddělení má deset souvisejících kurzů. Výsledkem příkladu s dychtivým načítáním by byl jen jeden dotaz (join) a jedna cesta k databázi. Opožděné načítání a explicitní načítání příkladů by vedlo k jedenácti dotazům a jedenácti odezvám do databáze. Dodatečné doby odezvy do databáze jsou zvláště škodlivé pro výkon při vysoké latenci.

Na druhou stranu v některých scénářích je opožděné načítání efektivnější. Dychtivé načítání může způsobit vygenerování velmi složitého spojení, které SQL Server nedokáže efektivně zpracovat. Nebo pokud potřebujete získat přístup k navigačním vlastnostem entity pouze pro podmnožinu zpracovávaných entit, může opožděné načítání fungovat lépe, protože by se načetlo více dat, než potřebujete. Pokud je výkon kritický, je nejlepší otestovat ho oběma způsoby, abyste mohli zvolit tu nejlepší volbu.

Obvykle byste použili explicitní načítání, pouze pokud jste vypnuli opožděné načítání. Jedním ze scénářů, kdy byste měli vypnout opožděné načítání, je během serializace. Opožděné načítání a serializace se dobře nekombinují, a pokud nejste opatrní, můžete nakonec dotazovat výrazně více dat, než jste zamýšleli, když je povolené opožděné načítání. Serializace obecně funguje tak, že přístup k každé vlastnosti instance typu. Přístup k vlastnostem aktivuje opožděné načítání a tyto líně načtené entity jsou serializovány. Proces serializace pak přistupuje ke každé vlastnosti opožděně načtených entit, což může způsobit ještě více opožděné načítání a serializace. Chcete-li zabránit této utíknutí řetězové reakce, vypněte opožděné načítání před serializací entity.

Třída kontextu databáze provádí ve výchozím nastavení opožděné načítání. Existují dva způsoby, jak zakázat opožděné načítání:

  • Pro konkrétní navigační vlastnosti vyněžte virtual klíčové slovo při deklaraci vlastnosti.

  • Pro všechny vlastnosti navigace nastavte LazyLoadingEnabled na false. Do konstruktoru třídy kontextu můžete například vložit následující kód:

    this.Configuration.LazyLoadingEnabled = false;
    

Opožděné načítání může maskovat kód, který způsobuje problémy s výkonem. Například kód, který neurčuje dychtivé nebo explicitní načítání, ale zpracovává velké množství entit a v každé iteraci používá několik navigačních vlastností, může být velmi neefektivní (z důvodu mnoha cest do databáze). Aplikace, která dobře funguje při vývoji pomocí místního SQL Serveru, může mít při přesunu do Azure SQL Database problémy s výkonem z důvodu zvýšené latence a opožděného načítání. Profilace databázových dotazů s realistickým testovacím zatížením vám pomůže určit, jestli je opožděné načítání vhodné. Další informace najdete v tématech Demystifikace strategií Entity Framework: Načítání souvisejících dat a Použití Entity Framework ke snížení latence sítě na SQL Azure.

Vytvoření indexové stránky kurzů, která zobrazuje název oddělení

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 s názvem CourseController pro Course typ entity pomocí stejných možností, které jste předtím použili pro Student kontroler, jak je znázorněno na následujícím obrázku (s výjimkou obrázku je vaše třída kontextu v oboru názvů DAL, ne v oboru názvů Models):

Add_Controller_dialog_box_for_Course_controller

Otevřete soubor Controllers\CourseController.cs a podívejte se na metodu Index :

public ViewResult Index()
{
    var courses = db.Courses.Include(c => c.Department);
    return View(courses.ToList());
}

Automatické generování uživatelského rozhraní určilo nedočkavé načítání pro Department vlastnost navigace pomocí Include metody .

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

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

Provedli jste následující změny v vygenerovaného kódu:

  • Změnili jsme nadpis z Index na Courses (Kurzy).
  • Odkazy řádků se přesunuly doleva.
  • Pod nadpisEm Číslo byl přidán sloupec, 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 záhlaví posledního sloupce z DepartmentID (název cizího klíče entity Department ) na Oddělení.

Všimněte si, že pro poslední sloupec zobrazí vygenerovaný kód Name vlastnost Department entity, která je načtená do Department vlastnosti navigace:

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

Spusťte stránku (na domovské stránce Contoso University vyberte kartu Kurzy ) a zobrazte seznam s názvy oddělení.

Courses_index_page_with_department_names

Vytvoření indexové stránky instruktorů, která zobrazuje kurzy a zápisy

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

Snímek obrazovky zobrazující stránku s indexem instruktora s instruktorem a vybraným jedním z jeho kurzů

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

  • Seznam instruktorů zobrazuje související data z OfficeAssignment entity. Entity Instructor a OfficeAssignment jsou v relaci 1:0 nebo 1. Pro entity použijete dychtivé OfficeAssignment načítání. Jak jsme si vysvětlili dříve, načítání dychtivých dat je obvykle efektivnější, když potřebujete související data pro všechny načtené řádky primární tabulky. V tomto případě chcete zobrazit přiřazení kanceláře pro všechny zobrazené instruktory.
  • Když uživatel vybere instruktora, zobrazí se související Course entity. Entity Instructor a Course jsou v relaci M:N. Pro entity a související Department entity použijete dychtivé Course načítání. V takovém případě může být opožděné načítání efektivnější, protože kurzy potřebujete jenom pro vybraného instruktora. Tento příklad však ukazuje, jak použít dychtivé načítání pro navigační vlastnosti v rámci entit, které jsou samy v navigačních vlastnostech.
  • Když uživatel vybere kurz, zobrazí se Enrollments související data ze sady entit. Entity Course a Enrollment jsou v relaci 1:N. Přidáte explicitní načítání entit Enrollment a souvisejících Student entit. (Explicitní načítání není nutné, protože je povolené opožděné načítání, ale to ukazuje, jak provést explicitní načítání.)

Vytvoření modelu zobrazení pro indexové zobrazení instruktora

Na stránce Index instruktora se zobrazují tři různé tabulky. Proto vytvoříte model zobrazení, který obsahuje tři vlastnosti, z nichž každá obsahuje data jedné z tabulek.

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

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

Přidání stylu pro vybrané řádky

K označení vybraných řádků potřebujete jinou barvu pozadí. Pokud chcete poskytnout styl pro toto uživatelské rozhraní, přidejte do oddílu /* info and errors */Content\Site.css následující zvýrazněný kód, jak je znázorněno níže:

/* info and errors */
.selectedrow 
{ 
    background-color: #a4d4e6; 
}
.message-info {
    border: 1px solid;
    clear: both;
    padding: 10px 20px;
}

Vytvoření kontroleru instruktora a zobrazení

Vytvořte InstructorController kontroler, jak je znázorněno na následujícím obrázku:

Add_Controller_dialog_box_for_Instructor_controller

Otevřete soubor Controllers\InstructorController.cs a přidejte using příkaz pro ViewModels obor názvů:

using ContosoUniversity.ViewModels;

Vygenerovaný kód v Index metodě určuje nedočkavé načítání pouze pro OfficeAssignment vlastnost navigace:

public ViewResult Index()
{
    var instructors = db.Instructors.Include(i => i.OfficeAssignment);
    return View(instructors.ToList());
}

Nahraďte metodu Index následujícím kódem, který načte další související data a vloží je do modelu zobrazení:

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);
}

Metoda přijímá volitelná data trasy (id) a parametr řetězce dotazu (courseID), které poskytují hodnoty ID vybraného instruktora a vybraného kurzu, a předá všechna požadovaná data do zobrazení. Parametry jsou poskytovány výběrem hypertextových odkazů na stránce.

Tip

Směrování dat

Směrovací data jsou data, která modelový pořadač našel v segmentu adresy URL zadaném ve směrovací tabulce. Výchozí trasa například určuje controller, actiona id segmenty:

routes.MapRoute(  
 name: "Default",  
 url: "{controller}/{action}/{id}",  
 defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }  
);

Na následující adrese URL se výchozí trasa mapuje Instructor jako controller, Index jako action a 1 jako id. Jedná se o datové hodnoty trasy.

http://localhost:1230/Instructor/Index/1?courseID=2021

"?courseID=2021" je hodnota řetězce dotazu. Pořadač modelu bude fungovat také v případě, že jako hodnotu řetězce dotazu předáte id hodnotu:

http://localhost:1230/Instructor/Index?id=1&CourseID=2021

Adresy URL se vytvářejí příkazy ActionLink v zobrazení Razor. V následujícím kódu id se parametr shoduje s výchozí trasou, takže id se přidá do dat trasy.

@Html.ActionLink("Select", "Index", new { id = item.PersonID  })

V následujícím kódu courseID neodpovídá parametru ve výchozí trase, takže se přidá jako řetězec dotazu.

@Html.ActionLink("Select", "Index", new { courseID = item.CourseID })

Kód začíná vytvořením instance modelu zobrazení a zařazením seznamu instruktorů. Kód určuje nedočkavé načítání vlastnosti Instructor.OfficeAssignment a Instructor.Courses navigation.

var viewModel = new InstructorIndexData();
viewModel.Instructors = db.Instructors
    .Include(i => i.OfficeAssignment)
    .Include(i => i.Courses.Select(c => c.Department))
     .OrderBy(i => i.LastName);

Druhá Include metoda načte kurzy a pro každý kurz, který je načten, se načte dychtivě pro Course.Department vlastnost navigace.

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

Jak už bylo zmíněno dříve, nedočkavé načítání se nevyžaduje, ale provádí se za účelem zvýšení výkonu. Vzhledem k tomu, že zobrazení vždy vyžaduje entitu OfficeAssignment , je efektivnější ji načíst ve stejném dotazu. Course Entity jsou vyžadovány, když je na webové stránce vybrán instruktor, takže dychtivé načítání je lepší než opožděné načítání pouze v případě, že se stránka zobrazuje častěji s vybraným kurzem než bez.

Pokud bylo vybráno ID instruktora, vybraný instruktor se načte ze seznamu instruktorů v modelu zobrazení. Vlastnost modelu Courses zobrazení se pak načte Course s entitami z navigační vlastnosti daného instruktora Courses .

if (id != null)
{
    ViewBag.InstructorID = id.Value;
    viewModel.Courses = viewModel.Instructors.Where(i => i.InstructorID == id.Value).Single().Courses;
}

Metoda Where vrátí kolekci, ale v tomto případě kritéria předaná této metodě způsobí, že se vrátí pouze jedna Instructor entita. Metoda Single převede kolekci na jednu Instructor entitu, která vám poskytne přístup k vlastnosti této entity Courses .

Metodu Single použijete u kolekce, pokud víte, že kolekce bude obsahovat pouze jednu položku. Metoda Single vyvolá výjimku, pokud je kolekce předaná do ní prázdná nebo pokud existuje více než jedna položka. Alternativou je SingleOrDefault, která vrací výchozí hodnotu (null v tomto případě), pokud je kolekce prázdná. V tomto případě by to však stále vedlo k výjimce (od pokusu Courses o nalezení vlastnosti u null odkazu) 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 místo volání Where metody samostatně:

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

Namísto:

.Where(I => i.InstructorID == id.Value).Single()

Pokud byl dále vybrán kurz, vybraný kurz se načte ze seznamu kurzů v modelu zobrazení. Potom se vlastnost modelu Enrollments zobrazení načte Enrollment s entitami z navigační vlastnosti daného kurzu Enrollments .

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

Úprava zobrazení indexu instruktora

V souboru Views\Instructor\Index.cshtml nahraďte existující kód následujícím kódem. Změny jsou zvýrazněné:

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

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

  • Změnila se třída modelu na InstructorIndexData.

  • Změnil se název stránky z Index na Instruktory.

  • Přesunutí sloupců s odkazem na řádek doleva

  • Byl odebrán sloupec FullName .

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

    <td> 
        @if (item.OfficeAssignment != null) 
        { 
            @item.OfficeAssignment.Location  
        } 
    </td>
    
  • Byl přidán kód, který bude dynamicky přidávat class="selectedrow" do tr prvku vybraného instruktora. Tím nastavíte barvu pozadí vybraného řádku pomocí třídy CSS, kterou jste vytvořili dříve. (Atribut valign bude užitečný v následujícím kurzu, když do tabulky přidáte sloupec s více řádky.)

    string selectedRow = ""; 
    if (item.InstructorID == ViewBag.InstructorID) 
    { 
        selectedRow = "selectedrow"; 
    } 
    <tr class="@selectedRow" valign="top">
    
  • Přidání nového ActionLink popisku Select bezprostředně před ostatní odkazy v každém řádku, což způsobí, že vybrané ID instruktora Index se odešle do metody.

Spusťte aplikaci a vyberte kartu Instruktoři . Stránka zobrazí Location vlastnost souvisejících OfficeAssignment entit a prázdnou buňku tabulky, pokud neexistuje žádná související OfficeAssignment entita.

Instructors_index_page_with_nothing_selected

V souboru Views\Instructor\Index.cshtml přidejte za uzavírací table prvek (na konci souboru) následující zvýrazněný kód. Zobrazí se seznam kurzů souvisejících s instruktorem při výběru instruktora.

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

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

Poznámka

Soubory .css se ukládají do mezipaměti prohlížečů. Pokud se změny při spuštění aplikace nezobrazí, proveďte pevnou aktualizaci (podržte stisknutou klávesu CTRL a klikněte na tlačítko Aktualizovat nebo stiskněte kombinaci kláves CTRL+F5).

Spusťte stránku a vyberte instruktora. Teď se zobrazí mřížka, 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_with_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 do kurzu zapsáni, když je tento kurz vybrán.

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

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

Spusťte stránku a vyberte instruktora. Pak vyberte kurz a zobrazte seznam zaregistrovaných studentů a jejich známek.

Snímek obrazovky se stránkou Index instruktorů s vybraným instruktorem a jedním z jeho kurzů

Přidání explicitního načítání

Otevřete soubor InstructorController.cs a podívejte se, jak Index metoda získá seznam registrací pro vybraný kurz:

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

Když jste získali seznam instruktorů, zadali jste dychtivé načítání pro Courses vlastnost navigace a vlastnost Department každého kurzu. Potom vložíte kolekci Courses do modelu zobrazení a teď přistupujete k Enrollments vlastnosti navigace z jedné entity v této kolekci. Vzhledem k tomu, že jste pro Course.Enrollments vlastnost navigace nezadali nedočkavé načítání, zobrazují se data z této vlastnosti na stránce v důsledku opožděného načítání.

Pokud jste zakázali opožděné načítání bez jakékoli jiné změny kódu, Enrollments vlastnost by byla null bez ohledu na počet registrací, které kurz skutečně měl. V takovém případě byste museli pro načtení Enrollments vlastnosti zadat buď dychtivé načítání, nebo explicitní načtení. Už jste viděli, jak provádět dychtivé načítání. Pokud chcete vidět příklad explicitního načtení, nahraďte metodu Index následujícím kódem, který explicitně načte Enrollments vlastnost. Změněný kód je zvýrazněný.

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);
}

Po získání vybrané Course entity nový kód explicitně načte navigační vlastnost kurzu Enrollments :

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

Pak explicitně načte související Student entitu každé Enrollment entity:

db.Entry(enrollment).Reference(x => x.Student).Load();

Všimněte si, že používáte metodu Collection k načtení vlastnosti kolekce, ale pro vlastnost, která obsahuje pouze jednu entitu, použijete metodu Reference . Teď můžete spustit stránku Index instruktora a neuvidíte žádný rozdíl v tom, co se na stránce zobrazuje, i když jste změnili způsob načítání dat.

Souhrn

Teď jste použili všechny tři způsoby (líné, dychtivé a explicitní) k načtení souvisejících dat do navigačních vlastností. V dalším kurzu se dozvíte, jak aktualizovat související data.

Odkazy na další prostředky Entity Framework najdete v mapě obsahu ASP.NET Data Access.