Udostępnij za pośrednictwem


Odczytywanie powiązanych danych z platformą Entity Framework w aplikacji MVC ASP.NET (5 z 10)

Autor : Tom Dykstra

Przykładowa aplikacja internetowa Contoso University pokazuje, jak utworzyć aplikacje ASP.NET MVC 4 przy użyciu programu Entity Framework 5 Code First i Visual Studio 2012. Aby uzyskać informacje na temat serii samouczków, zobacz pierwszy samouczek z serii.

Uwaga

Jeśli napotkasz problem, którego nie możesz rozwiązać, pobierz ukończony rozdział i spróbuj odtworzyć problem. Zazwyczaj rozwiązanie problemu można znaleźć, porównując kod z ukończonym kodem. Aby uzyskać informacje o niektórych typowych błędach i sposobach ich rozwiązywania, zobacz Błędy i obejścia.

W poprzednim samouczku ukończono model danych szkoły. W tym samouczku odczytasz i wyświetlisz powiązane dane — czyli dane ładowane przez program Entity Framework do właściwości nawigacji.

Na poniższych ilustracjach przedstawiono strony, z którymi będziesz pracować.

Zrzut ekranu przedstawiający stronę Indeks kursów uniwersyteckich firmy Contoso.

Zrzut ekranu przedstawiający stronę Indeks instruktorów uniwersytetu Contoso z wybranym instruktorem i jednym z wybranych kursów.

Istnieje kilka sposobów ładowania powiązanych danych przez program Entity Framework do właściwości nawigacji jednostki:

  • Ładowanie z opóźnieniem. Gdy jednostka jest najpierw odczytywana, powiązane dane nie są pobierane. Jednak po raz pierwszy próbujesz uzyskać dostęp do właściwości nawigacji, dane wymagane dla tej właściwości nawigacji są pobierane automatycznie. Powoduje to wysłanie wielu zapytań do bazy danych — jeden dla samej jednostki i jeden za każdym razem, gdy należy pobrać powiązane dane dla jednostki.

    Lazy_loading_example

  • Chętny do ładowania. Gdy jednostka jest odczytywana, powiązane dane są pobierane wraz z nim. Zazwyczaj powoduje to utworzenie pojedynczego zapytania sprzężenia, które pobiera wszystkie potrzebne dane. Można określić chętne ładowanie przy użyciu Include metody .

    Eager_loading_example

  • Jawne ładowanie. Jest to podobne do ładowania leniwego, z wyjątkiem tego, że jawnie pobierasz powiązane dane w kodzie; nie występuje automatycznie po uzyskiwaniu dostępu do właściwości nawigacji. Dane powiązane są ładowane ręcznie przez pobranie wpisu menedżera stanu obiektu dla jednostki i wywołanie Collection.Load metody kolekcji lub Reference.Load metody właściwości, które przechowują pojedynczą jednostkę. (W poniższym przykładzie, jeśli chcesz załadować właściwość nawigacji administratora, zastąpisz ciąg Collection(x => x.Courses) . Reference(x => x.Administrator))

    Explicit_loading_example

Ponieważ nie pobierają natychmiast wartości właściwości, ładowanie leniwe i jawne ładowanie są również nazywane ładowaniem odroczonym.

Ogólnie rzecz biorąc, jeśli wiesz, że potrzebujesz powiązanych danych dla każdej pobranej jednostki, chętne ładowanie oferuje najlepszą wydajność, ponieważ pojedyncze zapytanie wysyłane do bazy danych jest zazwyczaj bardziej wydajne niż oddzielne zapytania dla każdej pobranej jednostki. Na przykład w powyższych przykładach załóżmy, że każdy dział ma dziesięć powiązanych kursów. Przykład chętnego ładowania spowoduje utworzenie pojedynczego zapytania (sprzężenia) i pojedynczej rundy do bazy danych. Leniwe ładowanie i jawne przykłady ładowania spowodują zarówno jedenaście zapytań, jak i jedenaście rund do bazy danych. Dodatkowe runda do bazy danych są szczególnie szkodliwe dla wydajności, gdy opóźnienie jest wysokie.

Z drugiej strony w niektórych scenariuszach ładowanie leniwe jest bardziej wydajne. Chętne ładowanie może spowodować wygenerowanie bardzo złożonego sprzężenia, które SQL Server nie może wydajnie przetworzyć. Lub jeśli potrzebujesz dostępu do właściwości nawigacji jednostki tylko dla podzestawu zestawu jednostek, które przetwarzasz, ładowanie leniwe może działać lepiej, ponieważ chętne ładowanie pobiera więcej danych niż potrzebujesz. Jeśli wydajność jest krytyczna, najlepiej przetestować wydajność na oba sposoby, aby dokonać najlepszego wyboru.

Zazwyczaj używa się jawnego ładowania tylko wtedy, gdy ładowanie jest wyłączone. Jednym ze scenariuszy, w którym należy wyłączyć ładowanie, jest proces serializacji. Ładowanie z opóźnieniem i serializacja nie są dobrze mieszane, a jeśli nie jesteś ostrożny, możesz wykonać zapytanie znacznie więcej danych niż zamierzone, gdy ładowanie leniwe jest włączone. Serializacja zwykle działa przez uzyskanie dostępu do każdej właściwości w wystąpieniu typu. Dostęp do właściwości wyzwalaczy leniwego ładowania, a te leniwe załadowane jednostki są serializowane. Następnie proces serializacji uzyskuje dostęp do każdej właściwości jednostek załadowanych z opóźnieniem, co może spowodować jeszcze większe opóźnienie ładowania i serializacji. Aby zapobiec tej reakcji łańcucha ucieczki, wyłącz ładowanie leniwe przed serializacji jednostki.

Klasa kontekstu bazy danych domyślnie wykonuje ładowanie opóźnione. Istnieją dwa sposoby wyłączania ładowania leniwego:

  • W przypadku określonych właściwości nawigacji pomiń virtual słowo kluczowe podczas deklarowania właściwości.

  • Dla wszystkich właściwości nawigacji ustaw wartość LazyLoadingEnabledfalse. Można na przykład umieścić następujący kod w konstruktorze klasy kontekstu:

    this.Configuration.LazyLoadingEnabled = false;
    

Ładowanie leniwe może maskować kod, który powoduje problemy z wydajnością. Na przykład kod, który nie określa chętnego lub jawnego ładowania, ale przetwarza dużą liczbę jednostek i używa kilku właściwości nawigacji w każdej iteracji może być bardzo nieefektywny (ze względu na wiele rund do bazy danych). Aplikacja, która dobrze sprawdza się podczas programowania przy użyciu lokalnego serwera SQL, może mieć problemy z wydajnością podczas przenoszenia do bazy danych Azure SQL z powodu zwiększonego opóźnienia i opóźnionego ładowania. Profilowanie zapytań bazy danych przy realistycznym obciążeniu testowym pomoże określić, czy ładowanie z opóźnieniem jest odpowiednie. Aby uzyskać więcej informacji, zobacz Demystifying Entity Framework Strategies: ładowanie powiązanych danych i używanie programu Entity Framework w celu zmniejszenia opóźnienia sieci do Usługi SQL Azure.

Tworzenie strony indeksu kursów, która wyświetla nazwę działu

Jednostka Course zawiera właściwość nawigacji zawierającą Department jednostkę działu, do której przypisano kurs. Aby wyświetlić nazwę przypisanego działu na liście kursów, należy pobrać Name właściwość z Department jednostki, która znajduje się we Course.Department właściwości nawigacji.

Utwórz kontroler o nazwie CourseController dla Course typu jednostki przy użyciu tych samych opcji, które zostały wcześniej utworzone dla Student kontrolera, jak pokazano na poniższej ilustracji (z wyjątkiem tego obrazu, klasa kontekstu znajduje się w przestrzeni nazw DAL, a nie w przestrzeni nazw Modele):

Add_Controller_dialog_box_for_Course_controller

Otwórz plik Controllers\CourseController.cs i przyjrzyj się metodzie Index :

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

Automatyczne tworzenie szkieletów określiło chętne ładowanie właściwości Department nawigacji przy użyciu Include metody .

Otwórz plik Views\Course\Index.cshtml i zastąp istniejący kod następującym kodem. Zmiany są wyróżnione:

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

Wprowadzono następujące zmiany w kodzie szkieletowym:

  • Zmieniono nagłówek z Indeks na Kursy.
  • Przeniesiono łącza wiersza do lewej strony.
  • Dodano kolumnę pod nagłówkiem Liczba , która pokazuje CourseID wartość właściwości. (Domyślnie klucze podstawowe nie są szkieletowe, ponieważ zwykle są one bez znaczenia dla użytkowników końcowych. Jednak w tym przypadku klucz podstawowy ma znaczenie i chcesz go pokazać).
  • Zmieniono ostatni nagłówek kolumny z DepartmentID (nazwa klucza obcego Department na jednostkę) na Dział.

Zwróć uwagę, że w przypadku ostatniej kolumny kod szkieletowy wyświetla Name właściwość Department jednostki załadowanej do Department właściwości nawigacji:

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

Uruchom stronę (wybierz kartę Kursy na stronie głównej Contoso University), aby wyświetlić listę z nazwami działów.

Courses_index_page_with_department_names

Tworzenie strony indeksu instruktorów zawierającej kursy i rejestracje

W tej sekcji utworzysz kontroler i wyświetlisz dla Instructor jednostki, aby wyświetlić stronę Indeks instruktorów:

Zrzut ekranu przedstawiający stronę Indeks instruktorów z wybranym instruktorem i jednym z wybranych kursów.

Ta strona odczytuje i wyświetla powiązane dane w następujący sposób:

  • Lista instruktorów zawiera powiązane dane z OfficeAssignment jednostki. Instructor Jednostki i OfficeAssignment znajdują się w relacji jeden do zera lub jednego. Użyjesz chętnego OfficeAssignment ładowania dla jednostek. Jak wyjaśniono wcześniej, ładowanie chętne jest zwykle bardziej wydajne, gdy potrzebne są powiązane dane dla wszystkich pobranych wierszy tabeli podstawowej. W takim przypadku chcesz wyświetlić przypisania biura dla wszystkich wyświetlanych instruktorów.
  • Gdy użytkownik wybierze instruktora, zostaną wyświetlone powiązane Course jednostki. Instructor Jednostki i Course znajdują się w relacji wiele-do-wielu. Użyjesz chętnego Course ładowania dla jednostek i powiązanych z Department nimi jednostek. W takim przypadku ładowanie leniwe może być bardziej wydajne, ponieważ potrzebujesz kursów tylko dla wybranego instruktora. W tym przykładzie pokazano jednak, jak używać funkcji ładowania chętnego do ładowania właściwości nawigacji we właściwościach nawigacji.
  • Gdy użytkownik wybierze kurs, zostaną wyświetlone powiązane dane z Enrollments zestawu jednostek. Course Jednostki i Enrollment znajdują się w relacji jeden do wielu. Dodasz jawne ładowanie jednostek Enrollment i powiązanych jednostek Student . (Jawne ładowanie nie jest konieczne, ponieważ jest włączone ładowanie leniwe, ale pokazuje to, jak przeprowadzić jawne ładowanie).

Tworzenie modelu widoku dla widoku indeksu instruktora

Na stronie Indeks instruktora są wyświetlane trzy różne tabele. W związku z tym utworzysz model widoku zawierający trzy właściwości, z których każda przechowuje dane dla jednej z tabel.

W folderze ViewModels utwórz plik InstructorIndexData.cs i zastąp istniejący kod następującym kodem:

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

Dodawanie stylu dla wybranych wierszy

Aby oznaczyć wybrane wiersze, potrzebujesz innego koloru tła. Aby podać styl dla tego interfejsu użytkownika, dodaj następujący wyróżniony kod do sekcji /* info and errors */ w pliku Content\Site.css, jak pokazano poniżej:

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

Tworzenie kontrolera instruktora i widoków

InstructorController Utwórz kontroler, jak pokazano na poniższej ilustracji:

Add_Controller_dialog_box_for_Instructor_controller

Otwórz plik Controllers\InstructorController.cs i dodaj instrukcję using dla ViewModels przestrzeni nazw:

using ContosoUniversity.ViewModels;

Kod szkieletowy w metodzie Index określa chętne ładowanie tylko dla OfficeAssignment właściwości nawigacji:

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

Zastąp metodę Index następującym kodem, aby załadować dodatkowe powiązane dane i umieścić ją w modelu widoku:

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 akceptuje opcjonalne dane trasy () i parametr ciągu zapytania (idcourseID), który dostarcza wartości identyfikatorów wybranego instruktora i wybranego kursu, i przekazuje wszystkie wymagane dane do widoku. Parametry są dostarczane przez hiperlinki Wybierz na stronie.

Porada

Dane trasy

Dane trasy to dane, które powiązanie modelu można znaleźć w segmencie adresu URL określonym w tabeli routingu. Na przykład trasa domyślna określa controller, actioni id segmenty:

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

W poniższym adresie URL domyślna trasa mapuje Instructor jako controllerwartości , Index jako action wartości i 1 jako id; są to wartości danych trasowania.

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

"?courseID=2021" to wartość ciągu zapytania. Powiązanie modelu będzie również działać, jeśli przekażesz id jako wartość ciągu zapytania:

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

Adresy URL są tworzone przez ActionLink instrukcje w widoku Razor. W poniższym kodzie id parametr jest zgodny z trasą domyślną, dlatego id jest dodawany do danych trasy.

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

W poniższym kodzie courseID parametr nie jest zgodny z parametrem w trasie domyślnej, dlatego jest dodawany jako ciąg zapytania.

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

Kod rozpoczyna się od utworzenia wystąpienia modelu widoku i wprowadzenia do niej listy instruktorów. Kod określa chętne ładowanie dla Instructor.OfficeAssignment właściwości i Instructor.Courses nawigacji.

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

Druga Include metoda ładuje kursy, a dla każdego załadowanego kursu trwa ładowanie Course.Department dla właściwości nawigacji.

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

Jak wspomniano wcześniej, chętne ładowanie nie jest wymagane, ale jest wykonywane w celu zwiększenia wydajności. Ponieważ widok zawsze wymaga OfficeAssignment jednostki, bardziej wydajne jest pobranie tej samej kwerendy. Course jednostki są wymagane po wybraniu instruktora na stronie internetowej, więc chętne ładowanie jest lepsze niż ładowanie leniwe tylko wtedy, gdy strona jest wyświetlana częściej z wybranym kursem niż bez.

Jeśli wybrano identyfikator instruktora, wybrany instruktor zostanie pobrany z listy instruktorów w modelu widoku. Właściwość modelu Courses widoku jest następnie ładowana z jednostkami Course z właściwości nawigacji tego instruktora Courses .

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

Metoda Where zwraca kolekcję, ale w tym przypadku kryteria przekazane do tej metody powodują zwrócenie tylko jednej Instructor jednostki. Metoda Single konwertuje kolekcję na pojedynczą Instructor jednostkę, która zapewnia dostęp do właściwości tej Courses jednostki.

Używasz metody Single w kolekcji, gdy wiesz, że kolekcja będzie miała tylko jeden element. Metoda Single zgłasza wyjątek, jeśli kolekcja przekazana do niej jest pusta lub jeśli istnieje więcej niż jeden element. Alternatywą jest SingleOrDefault, która zwraca wartość domyślną (null w tym przypadku), jeśli kolekcja jest pusta. Jednak w tym przypadku nadal wynik wyjątku (od próby znalezienia Courses właściwości w null odwołaniu), a komunikat o wyjątku będzie mniej wyraźnie wskazywać przyczynę problemu. Po wywołaniu Single metody można również przekazać Where warunek zamiast wywoływać Where metodę oddzielnie:

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

Zamiast:

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

Następnie, jeśli wybrano kurs, wybrany kurs zostanie pobrany z listy kursów w modelu widoku. Następnie właściwość modelu Enrollments widoku jest ładowana z Enrollment jednostkami z właściwości nawigacji tego Enrollments kursu.

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

Modyfikowanie widoku indeksu instruktora

W pliku Views\Instructor\Index.cshtml zastąp istniejący kod następującym kodem. Zmiany są wyróżnione:

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

Wprowadzono następujące zmiany w istniejącym kodzie:

  • Zmieniono klasę modelu na InstructorIndexData.

  • Zmieniono tytuł strony z Indeks na Instruktorzy.

  • Przeniesiono kolumny linku wiersza z lewej strony.

  • Usunięto kolumnę FullName .

  • Dodano kolumnę pakietu Office , która jest wyświetlana item.OfficeAssignment.Location tylko wtedy, gdy item.OfficeAssignment nie ma wartości null. (Ponieważ jest to relacja "jeden do zera lub jeden", może nie istnieć powiązana OfficeAssignment jednostka).

    <td> 
        @if (item.OfficeAssignment != null) 
        { 
            @item.OfficeAssignment.Location  
        } 
    </td>
    
  • Dodano kod, który będzie dynamicznie dodawany class="selectedrow" do tr elementu wybranego instruktora. Spowoduje to ustawienie koloru tła dla wybranego wiersza przy użyciu utworzonej wcześniej klasy CSS. (Atrybut valign będzie przydatny w poniższym samouczku podczas dodawania kolumny z wieloma wierszami do tabeli).

    string selectedRow = ""; 
    if (item.InstructorID == ViewBag.InstructorID) 
    { 
        selectedRow = "selectedrow"; 
    } 
    <tr class="@selectedRow" valign="top">
    
  • Dodano nową ActionLink etykietę Wybierz bezpośrednio przed innymi linkami w każdym wierszu, co powoduje wysłanie wybranego identyfikatora instruktora Index do metody.

Uruchom aplikację i wybierz kartę Instruktorzy . Strona wyświetla Location właściwość powiązanych OfficeAssignment jednostek i pustą komórkę tabeli, gdy nie ma powiązanej OfficeAssignment jednostki.

Instructors_index_page_with_nothing_selected

W pliku Views\Instructor\Index.cshtml po zamknięciu table elementu (na końcu pliku) dodaj następujący wyróżniony kod. Spowoduje to wyświetlenie listy kursów związanych z instruktorem po wybraniu 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> 
}

Ten kod odczytuje Courses właściwość modelu widoku, aby wyświetlić listę kursów. Udostępnia również Select hiperlink, który wysyła identyfikator wybranego kursu do Index metody akcji.

Uwaga

Plik CSS jest buforowany przez przeglądarki. Jeśli nie widzisz zmian podczas uruchamiania aplikacji, wykonaj twarde odświeżanie (przytrzymaj klawisz CTRL podczas klikania przycisku Odśwież lub naciśnij klawisze CTRL+F5).

Uruchom stronę i wybierz instruktora. Teraz zobaczysz siatkę, która wyświetla kursy przypisane do wybranego instruktora, a dla każdego kursu zostanie wyświetlona nazwa przypisanego działu.

Instructors_index_page_with_instructor_selected

Po dodaniu bloku kodu dodaj następujący kod. Spowoduje to wyświetlenie listy uczniów, którzy są zarejestrowani w kursie po wybraniu tego kursu.

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

Ten kod odczytuje Enrollments właściwość modelu widoku, aby wyświetlić listę uczniów zarejestrowanych w kursie.

Uruchom stronę i wybierz instruktora. Następnie wybierz kurs, aby wyświetlić listę zarejestrowanych uczniów i ich ocen.

Zrzut ekranu przedstawiający stronę Indeks instruktorów z wybranym instruktorem i jednym z wybranych kursów.

Dodawanie jawnego ładowania

Otwórz plik InstructorController.cs i sprawdź, jak Index metoda pobiera listę rejestracji dla wybranego kursu:

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

Po pobraniu listy instruktorów określono chętne ładowanie dla Courses właściwości nawigacji i dla Department właściwości każdego kursu. Następnie umieścisz Courses kolekcję w modelu widoku, a teraz uzyskujesz dostęp do Enrollments właściwości nawigacji z jednej jednostki w tej kolekcji. Ponieważ nie określono chętnego Course.Enrollments ładowania dla właściwości nawigacji, dane z tej właściwości są wyświetlane na stronie w wyniku leniwego ładowania.

Jeśli wyłączono ładowanie leniwe bez zmiany kodu w jakikolwiek inny sposób, Enrollments właściwość będzie mieć wartość null niezależnie od liczby rejestracji, które faktycznie miały kurs. W takim przypadku, aby załadować Enrollments właściwość, należy określić chętne ładowanie lub jawne ładowanie. Wiesz już, jak zrobić chętny do ładowania. Aby zobaczyć przykład jawnego ładowania, zastąp Index metodę następującym kodem, który jawnie ładuje Enrollments właściwość. Zmieniono kod.

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 otrzymaniu wybranej Course jednostki nowy kod jawnie ładuje właściwość nawigacji tego Enrollments kursu:

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

Następnie jawnie ładuje jednostkę powiązaną Student z każdą Enrollment jednostką:

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

Zwróć uwagę, że metoda służy Collection do ładowania właściwości kolekcji, ale dla właściwości, która zawiera tylko jedną jednostkę, należy użyć Reference metody . Teraz możesz uruchomić stronę Indeks instruktora i nie zobaczysz różnicy w tym, co jest wyświetlane na stronie, chociaż zmieniono sposób pobierania danych.

Podsumowanie

Użyto już wszystkich trzech sposobów (leniwych, chętnych i jawnych) w celu załadowania powiązanych danych do właściwości nawigacji. W następnym samouczku dowiesz się, jak zaktualizować powiązane dane.

Linki do innych zasobów platformy Entity Framework można znaleźć na mapie zawartości dostępu do danych ASP.NET.