Udostępnij za pośrednictwem


Samouczek: odczytywanie powiązanych danych z platformą EF w aplikacji MVC ASP.NET

W poprzednim samouczku ukończono model danych Szkoły. W tym samouczku będziesz odczytywać i wyświetlać 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ę Kursy z listą kursów.

Instructors_index_page_with_instructor_and_course_selected

Pobieranie ukończonego projektu

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

W tym samouczku zostały wykonane następujące czynności:

  • Dowiedz się, jak ładować powiązane dane
  • Tworzenie strony Kursy
  • Tworzenie strony Instruktorzy

Wymagania wstępne

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

  • Ładowanie leniwe. Gdy jednostka jest najpierw odczytywana, powiązane dane nie są pobierane. Jednak przy pierwszej próbie uzyskania dostępu do właściwości nawigacji pobierane są automatycznie dane wymagane dla tej właściwości nawigacji. Powoduje to wysłanie wielu zapytań do bazy danych — po jednym dla samej jednostki i po jednym za każdym razem, gdy należy pobrać powiązane dane dla jednostki. Klasa DbContext domyślnie włącza ładowanie z opóźnieniem.

    Lazy_loading_example

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

    Eager_loading_example

  • Jawne ładowanie. Jest to podobne do leniwego ładowania, z tą różnicą, że jawnie pobierasz powiązane dane w kodzie; nie występuje automatycznie, gdy uzyskujesz dostęp 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 metody Collection.Load dla kolekcji lub metody Reference.Load dla właściwości zawierających jedną jednostkę. (W poniższym przykładzie, jeśli chcesz załadować właściwość nawigacji Administrator, możesz zastąpić ciąg Collection(x => x.Courses) Reference(x => x.Administrator).) Zazwyczaj należy użyć jawnego ładowania tylko wtedy, gdy opóźniono ładowanie.

    Explicit_loading_example

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

Zagadnienia dotyczące wydajności

Jeśli wiesz, że potrzebujesz powiązanych danych dla każdej pobranej jednostki, chętne ładowanie często zapewnia najlepszą wydajność, ponieważ pojedyncze zapytanie wysyłane do bazy danych jest zwykle 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 tylko jednego zapytania (sprzężenia) i pojedynczej rundy do bazy danych. Leniwe ładowanie i jawne przykłady ładowania spowodowałoby jedenaście zapytań i jedenaście rund do bazy danych. Dodatkowe rundy do bazy danych są szczególnie szkodliwe dla wydajności, gdy opóźnienie jest wysokie.

Z drugiej strony, w niektórych scenariuszach opóźnienie ładowania jest bardziej wydajne. Chętne ładowanie może spowodować wygenerowanie bardzo złożonego sprzężenia, którego program SQL Server nie może wydajnie przetworzyć. Jeśli jednak musisz uzyskać dostęp do właściwości nawigacji jednostki tylko dla podzestawu zestawu przetwarzanych jednostek, ł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.

Ł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 działa dobrze podczas programowania przy użyciu lokalnego serwera SQL, może mieć problemy z wydajnością po przeniesieniu do usługi Azure SQL Database 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 leniwe jest odpowiednie. Aby uzyskać więcej informacji, zobacz Demystifying Entity Framework Strategies: Loading Related Data and Using the Entity Framework to Reduce Network Latency to Usługi SQL Azure (Demystifying Entity Framework Strategies: Loading Related Data and Using the Entity Framework to Reduce Network Latency to Usługi SQL Azure).

Wyłącz ładowanie z opóźnieniem przed serializacji

Jeśli podczas serializacji pozostawisz włączone opóźnienie ładowania, możesz wykonać zapytanie o znacznie więcej danych niż zamierzone. 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 powoduje opóźnienie ładowania, a te leniwe załadowane jednostki są serializowane. Następnie proces serializacji uzyskuje dostęp do każdej właściwości jednostek ładowanych z opóźnieniem, co może spowodować jeszcze bardziej leniwe ładowanie i serializacji. Aby zapobiec tej reakcji łańcucha ucieczki, przed serializacji jednostki należy wyłączyć opóźnienie ładowania.

Serializacja może być również skomplikowana przez klasy serwera proxy używane przez program Entity Framework, zgodnie z opisem w samouczku Advanced Scenarios (Scenariusze zaawansowane).

Jednym ze sposobów uniknięcia problemów z serializacji jest serializowanie obiektów transferu danych (DTO) zamiast obiektów jednostek, jak pokazano w samouczku Using Web API with Entity Framework (Korzystanie z internetowego interfejsu API z platformą Entity Framework ).

Jeśli nie używasz obiektów DTO, możesz wyłączyć leniwe ładowanie i uniknąć problemów z serwerem proxy, wyłączając tworzenie serwera proxy.

Poniżej przedstawiono kilka innych sposobów 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 LazyLoadingEnabled falsewartość , umieść następujący kod w konstruktorze klasy kontekstu:

    this.Configuration.LazyLoadingEnabled = false;
    

Tworzenie strony Kursy

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, musisz 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 (nie CoursesController) dla Course typu jednostki, używając tych samych opcji dla kontrolera MVC 5 z widokami za pomocą szkieletu Student programu Entity Framework, który został wcześniej utworzony dla kontrolera:

Ustawienie Wartość
Klasa modelu Wybierz pozycję Kurs (ContosoUniversity.Models).
Klasa kontekstu danych Wybierz pozycję SchoolContext (ContosoUniversity.DAL).
Nazwa kontrolera Wprowadź CourseController. Ponownie, nie CoursesController z s. Po wybraniu opcji Kurs (ContosoUniversity.Models) wartość nazwy kontrolera została automatycznie wypełniona. Musisz zmienić wartość.

Pozostaw pozostałe wartości domyślne i dodaj kontroler.

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

public ActionResult 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 kod szablonu 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 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>

Wprowadzono następujące zmiany w kodzie szkieletowym:

  • Zmieniono nagłówek z Indeks na Kursy.
  • Dodano kolumnę Number (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 jest zrozumiały i chcesz go pokazać.
  • Przenieś kolumnę Department (Dział) po prawej stronie i zmieniono jej nagłówek. Szkielet poprawnie wybrał Name właściwość z Department jednostki, ale na stronie Kurs nagłówek kolumny powinien mieć wartość Dział , a nie Nazwa.

Zwróć uwagę, że w kolumnie Dział 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 Uniwersytetu Contoso), aby wyświetlić listę z nazwami działów.

Tworzenie strony Instruktorzy

W tej sekcji utworzysz kontroler i widok dla Instructor jednostki, aby wyświetlić stronę Instruktorzy. 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. Jednostki Instructor 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ć przydziały biurowe dla wszystkich wyświetlanych instruktorów.
  • Gdy użytkownik wybierze instruktora, zostaną wyświetlone powiązane Course jednostki. Jednostki Instructor 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ż potrzebne są kursy tylko dla wybranego instruktora. Jednak w tym przykładzie pokazano, jak używać chętnego ładowania do właściwości nawigacji w ramach samych jednostek we właściwościach nawigacji.
  • Gdy użytkownik wybierze kurs, zostaną wyświetlone powiązane dane z Enrollments zestawu jednostek. Jednostki Course 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 wykonać jawne ładowanie).

Tworzenie modelu widoku dla widoku indeksu instruktora

Na stronie Instruktorzy 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 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; }
    }
}

Tworzenie kontrolera instruktora i widoków

InstructorController Utwórz kontroler (nie InstruktorsController) z akcją odczytu/zapisu EF:

Ustawienie Wartość
Klasa modelu Wybierz pozycję Instruktor (ContosoUniversity.Models).
Klasa kontekstu danych Wybierz pozycję SchoolContext (ContosoUniversity.DAL).
Nazwa kontrolera Wprowadź ciąg InstructorController. Ponownie, a nie InstruktorzyController z s. Po wybraniu opcji Kurs (ContosoUniversity.Models) wartość nazwy kontrolera została automatycznie wypełniona. Musisz zmienić wartość.

Pozostaw pozostałe wartości domyślne i dodaj kontroler.

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

Metoda akceptuje opcjonalne dane trasy (id) i parametr ciągu zapytania (courseID), który dostarcza wartości identyfikatorów wybranego instruktora i wybranego kursu oraz przekazuje wszystkie wymagane dane do widoku. Parametry są udostępniane przez hiperlinki Wybierz na stronie.

Kod rozpoczyna się od utworzenia wystąpienia modelu widoku i umieszczenie go na liście 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 do właściwości nawigacji.

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

Jak wspomniano wcześniej, ładowanie chętne nie jest wymagane, ale jest wykonywane w celu zwiększenia wydajności. Ponieważ widok zawsze wymaga OfficeAssignment jednostki, bardziej wydajne jest pobranie tej jednostki w tym samym zapytaniu. Course jednostki są wymagane, gdy instruktor jest wybrany 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.ID == 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 wiadomo, ż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 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ć metodę Where oddzielnie:

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

Zamiast:

.Where(I => i.ID == 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 jednostkami Enrollment z właściwości nawigacji tego kursu Enrollments .

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 kod szablonu 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 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>

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

  • Zmieniono klasę modelu na InstructorIndexData.

  • Zmieniono tytuł strony z Indeks na Instruktorzy.

  • 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 jednego, być może nie ma powiązanej OfficeAssignment jednostki).

    <td> 
        @if (item.OfficeAssignment != null) 
        { 
            @item.OfficeAssignment.Location  
        } 
    </td>
    
  • Dodano kod, który będzie dynamicznie dodawany class="success" do tr elementu wybranego instruktora. Spowoduje to ustawienie koloru tła dla wybranego wiersza przy użyciu klasy Bootstrap.

    string selectedRow = ""; 
    if (item.InstructorID == ViewBag.InstructorID) 
    { 
        selectedRow = "success"; 
    } 
    <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.

W pliku Views\Instructor\Index.cshtml po elememencie zamykającym table (na końcu pliku) dodaj następujący kod. Ten kod wyświetla listę kursów związanych z instruktorem po wybraniu instruktora.

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

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

Uruchom stronę i wybierz instruktora. Teraz zostanie wyświetlona siatka zawierająca kursy przypisane do wybranego instruktora, a dla każdego kursu zostanie wyświetlona nazwa przypisanego działu.

Po dodaniu właśnie dodanego 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 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>
}

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.

Dodawanie jawnego ładowania

Otwórz 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 inny sposób, Enrollments właściwość będzie mieć wartość null niezależnie od liczby rejestracji, które rzeczywiście 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 robić chętne ładowanie. 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.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);
}

Po otrzymaniu wybranej Course jednostki nowy kod jawnie ładuje właściwość nawigacji tego kursu Enrollments :

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

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

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

Zwróć uwagę, że używasz Collection metody 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 .

Uruchom teraz stronę Indeks instruktora i nie zobaczysz różnicy w tym, co jest wyświetlane na stronie, chociaż zmieniono sposób pobierania danych.

Uzyskiwanie kodu

Pobieranie ukończonego projektu

Dodatkowe zasoby

Linki do innych zasobów programu Entity Framework można znaleźć w ASP.NET Dostęp do danych — zalecane zasoby.

Następne kroki

W tym samouczku zostały wykonane następujące czynności:

  • Dowiedz się, jak ładować powiązane dane
  • Utworzono stronę Kursy
  • Utworzono stronę Instruktorzy

Przejdź do następnego artykułu, aby dowiedzieć się, jak aktualizować powiązane dane.