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ć.
Leniwe, chętne i jawne ładowanie powiązanych danych
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.
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 .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 lubReference.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ągCollection(x => x.Courses)
.Reference(x => x.Administrator)
)
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ść
LazyLoadingEnabled
false
. 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):
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.
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:
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 iOfficeAssignment
znajdują się w relacji jeden do zera lub jednego. Użyjesz chętnegoOfficeAssignment
ł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 iCourse
znajdują się w relacji wiele-do-wielu. Użyjesz chętnegoCourse
ładowania dla jednostek i powiązanych zDepartment
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 iEnrollment
znajdują się w relacji jeden do wielu. Dodasz jawne ładowanie jednostekEnrollment
i powiązanych jednostekStudent
. (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:
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 (id
courseID
), 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
, action
i 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 controller
wartoś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, gdyitem.OfficeAssignment
nie ma wartości null. (Ponieważ jest to relacja "jeden do zera lub jeden", może nie istnieć powiązanaOfficeAssignment
jednostka).<td> @if (item.OfficeAssignment != null) { @item.OfficeAssignment.Location } </td>
Dodano kod, który będzie dynamicznie dodawany
class="selectedrow"
dotr
elementu wybranego instruktora. Spowoduje to ustawienie koloru tła dla wybranego wiersza przy użyciu utworzonej wcześniej klasy CSS. (Atrybutvalign
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 instruktoraIndex
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 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.
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.
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.