Esercitazione: Leggere i dati correlati - ASP.NET MVC con EF Core
Nell'esercitazione precedente è stato completato il modello di dati School. In questa esercitazione verranno letti e visualizzati dati correlati, ovvero dati che Entity Framework carica all'interno delle proprietà di navigazione.
Le figure seguenti illustrano le pagine che verranno usate.
In questa esercitazione:
- Scoprire come caricare i dati correlati
- Creare una pagina Courses
- Creare una pagina Instructors
- Ottenere informazioni sul caricamento esplicito
Prerequisiti
Scoprire come caricare i dati correlati
Il software ORM (Object-Relational Mapping), ad esempio Entity Framework, può caricare dati correlati nelle proprietà di navigazione di un'entità in diversi modi:
Caricamento eager: quando l'entità viene letta, i dati correlati vengono recuperati insieme a esso. Ciò in genere ha come risultato una query join singola che recupera tutti i dati necessari. Per specificare il caricamento eager in Entity Framework Core si usano i metodi
Include
eThenInclude
.È possibile recuperare alcuni dati tramite query separate. In questo caso EF "corregge" le proprietà di navigazione. In altre parole, EF aggiunge automaticamente le entità recuperate separatamente nelle proprietà di navigazione corrispondenti delle entità recuperate in precedenza. Per la query che recupera i dati correlati, è possibile usare il metodo
Load
anziché un metodo che restituisce un elenco o un oggetto, ad esempioToList
oSingle
.Caricamento esplicito: quando l'entità viene letta per la prima volta, i dati correlati non vengono recuperati. Il codice del caricamento consente di recuperare i dati correlati se sono necessari. Come nel caso del caricamento eager con query separate, il caricamento esplicito ha come risultato l'invio di più query al database. La differenza è che con il caricamento esplicito il codice specifica le proprietà di navigazione da caricare. In Entity Framework Core 1.1, per eseguire il caricamento esplicito è possibile usare il metodo
Load
. Ad esempio:Caricamento differita: quando l'entità viene letta per la prima volta, i dati correlati non vengono recuperati. La prima volta che si tenta di accedere a una proprietà di navigazione, tuttavia, i dati necessari per quest'ultima vengono recuperati automaticamente. Una query viene inviata al database ogni volta che si tenta di ottenere dati da una proprietà di navigazione per la prima volta. Entity Framework Core 1.0 non supporta il caricamento lazy.
Considerazioni sulle prestazioni
Se si sa di aver bisogno di dati correlati per tutte le entità recuperate, il caricamento eager spesso garantisce le prestazioni migliori, perché l'invio di un'unica query al database è in genere più efficiente dell'invio di query separate per ogni entità recuperata. Si supponga ad esempio che ogni dipartimento abbia dieci corsi correlati. Il caricamento eager di tutti i dati correlati comporta un'unica query (join) e un unico round trip al database. Una query separata per i corsi di ogni dipartimento comporta undici round trip al database. I round trip aggiuntivi al database influiscono in modo particolarmente negativo sulle prestazioni quando la latenza è elevata.
D'altra parte, in alcuni scenari query separate sono più efficienti. Il caricamento eager di tutti i dati correlati in una sola query può causare la generazione di un join molto complesso, che SQL Server non è in grado di elaborare in modo efficiente. Oppure se è necessario accedere alle proprietà di navigazione di un'entità solo per un subset di un set di entità in corso di elaborazione, query separate potrebbero offrire prestazioni migliori perché il caricamento immediato di tutti i dati recupererebbe più dati di quelli necessari. Se le prestazioni rappresentano un aspetto essenziale, per avere la certezza di scegliere il metodo più efficiente è consigliabile testare le prestazioni di entrambi i tipi di caricamento.
Creare una pagina Courses
L'entità Course
include una proprietà di navigazione che contiene l'entità Department
del reparto a cui è assegnato il corso. Per visualizzare il nome del reparto assegnato in un elenco di corsi, è necessario ottenere la Name
proprietà dall'entità Department
che si trova nella Course.Department
proprietà di navigazione.
Creare un controller denominato CoursesController
per il Course
tipo di entità usando le stesse opzioni per il controller MVC con viste, usando lo scaffolder di Entity Framework precedentemente eseguito per StudentsController
, come illustrato nella figura seguente:
Aprire CoursesController.cs
ed esaminare il Index
metodo . Lo scaffolding automatico ha specificato il caricamento eager per la proprietà di navigazione Department
tramite il metodo Include
.
Sostituire il metodo Index
con il codice seguente, che usa un nome più appropriato per l'IQueryable
che restituisce entità Course (courses
anziché schoolContext
):
public async Task<IActionResult> Index()
{
var courses = _context.Courses
.Include(c => c.Department)
.AsNoTracking();
return View(await courses.ToListAsync());
}
Aprire Views/Courses/Index.cshtml
e sostituire il codice del modello con il codice seguente. Le modifiche sono evidenziate:
@model IEnumerable<ContosoUniversity.Models.Course>
@{
ViewData["Title"] = "Courses";
}
<h2>Courses</h2>
<p>
<a asp-action="Create">Create New</a>
</p>
<table class="table">
<thead>
<tr>
<th>
@Html.DisplayNameFor(model => model.CourseID)
</th>
<th>
@Html.DisplayNameFor(model => model.Title)
</th>
<th>
@Html.DisplayNameFor(model => model.Credits)
</th>
<th>
@Html.DisplayNameFor(model => model.Department)
</th>
<th></th>
</tr>
</thead>
<tbody>
@foreach (var item in Model)
{
<tr>
<td>
@Html.DisplayFor(modelItem => item.CourseID)
</td>
<td>
@Html.DisplayFor(modelItem => item.Title)
</td>
<td>
@Html.DisplayFor(modelItem => item.Credits)
</td>
<td>
@Html.DisplayFor(modelItem => item.Department.Name)
</td>
<td>
<a asp-action="Edit" asp-route-id="@item.CourseID">Edit</a> |
<a asp-action="Details" asp-route-id="@item.CourseID">Details</a> |
<a asp-action="Delete" asp-route-id="@item.CourseID">Delete</a>
</td>
</tr>
}
</tbody>
</table>
Al codice con scaffolding sono state apportate le modifiche seguenti:
Modifica dell'intestazione da Indice a Corsi.
È stata aggiunta la colonna Number (Numero) con il valore della proprietà
CourseID
. Per impostazione predefinita, non viene eseguito lo scaffolding delle chiavi primarie, perché in genere non sono significative per gli utenti finali. In questo caso, tuttavia, la chiave primaria è significativa ed è necessario visualizzarla.Modificare la colonna Department (Dipartimento) per visualizzare il nome del dipartimento. Il codice visualizza la proprietà
Name
dell'entitàDepartment
che viene caricata nella proprietà di navigazioneDepartment
:@Html.DisplayFor(modelItem => item.Department.Name)
Eseguire l'app e selezionare la scheda Courses (Corsi) per visualizzare l'elenco con i nomi dei dipartimenti.
Creare una pagina Instructors
In questa sezione si creerà un controller e si visualizzerà l'entità per visualizzare la pagina Instructors :In this section, you'll create a controller and view for the Instructor
entity in to display the Instructors page:
Questa pagina legge e visualizza dati correlati nei modi seguenti:
L'elenco degli insegnanti visualizza i dati correlati dell'entità
OfficeAssignment
. Tra le entitàInstructor
eOfficeAssignment
c'è una relazione uno-a-zero-o-uno. Si userà il caricamento eager per leOfficeAssignment
entità. Come spiegato in precedenza, il caricamento eager è in genere più efficiente quando sono necessari i dati correlati per tutte le righe recuperate della tabella primaria. In questo caso, si vogliono visualizzare le assegnazioni di ufficio per tutti gli insegnanti visualizzati.Quando l'utente seleziona un insegnante, vengono visualizzate le entità
Course
correlate. Tra le entitàInstructor
eCourse
esiste una relazione molti-a-molti. Si userà il caricamento eager per leCourse
entità e le relative entità correlateDepartment
. In questo caso, query separate potrebbero essere più efficienti, perché i corsi sono necessari solo per l'insegnante selezionato. Questo esempio, tuttavia, illustra come usare il caricamento eager per le proprietà di navigazione con entità esse stesse all'interno di proprietà di navigazione.Quando l'utente seleziona un corso, vengono visualizzati i dati correlati dal
Enrollments
set di entità. Tra le entitàCourse
eEnrollment
esiste una relazione uno-a-molti. Si useranno query separate perEnrollment
le entità e le relative entità correlateStudent
.
Creare un modello per la visualizzazione dell'indice degli insegnanti
La pagina Instructors (Insegnanti) mostra i dati di tre tabelle diverse. Verrà quindi creato un modello di visualizzazione che includa tre proprietà, ognuna contenente i dati di una delle tabelle.
Nella cartella SchoolViewModels creare InstructorIndexData.cs
e sostituire il codice esistente con il codice seguente:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace ContosoUniversity.Models.SchoolViewModels
{
public class InstructorIndexData
{
public IEnumerable<Instructor> Instructors { get; set; }
public IEnumerable<Course> Courses { get; set; }
public IEnumerable<Enrollment> Enrollments { get; set; }
}
}
Creare il controller e le visualizzazioni per gli insegnanti
Creare un controller per gli insegnanti con azioni di lettura/scrittura EF come illustrato nella figura seguente:
Aprire InstructorsController.cs
e aggiungere un'istruzione using per lo spazio dei nomi ViewModels:
using ContosoUniversity.Models.SchoolViewModels;
Sostituire il metodo Index con il codice seguente per eseguire il caricamento eager di dati correlati e inserirlo nel modello di visualizzazione.
public async Task<IActionResult> Index(int? id, int? courseID)
{
var viewModel = new InstructorIndexData();
viewModel.Instructors = await _context.Instructors
.Include(i => i.OfficeAssignment)
.Include(i => i.CourseAssignments)
.ThenInclude(i => i.Course)
.ThenInclude(i => i.Enrollments)
.ThenInclude(i => i.Student)
.Include(i => i.CourseAssignments)
.ThenInclude(i => i.Course)
.ThenInclude(i => i.Department)
.AsNoTracking()
.OrderBy(i => i.LastName)
.ToListAsync();
if (id != null)
{
ViewData["InstructorID"] = id.Value;
Instructor instructor = viewModel.Instructors.Where(
i => i.ID == id.Value).Single();
viewModel.Courses = instructor.CourseAssignments.Select(s => s.Course);
}
if (courseID != null)
{
ViewData["CourseID"] = courseID.Value;
viewModel.Enrollments = viewModel.Courses.Where(
x => x.CourseID == courseID).Single().Enrollments;
}
return View(viewModel);
}
Il metodo accetta dati di route facoltativi (id
) e un parametro di stringa di query (courseID
) che forniscono i valori relativi all'ID dell'insegnante e del corso selezionati. I parametri sono forniti dai collegamenti ipertestuali Select (Seleziona) nella pagina.
Il codice inizia creando un'istanza del modello di visualizzazione e inserendola nell'elenco degli insegnanti. Il codice specifica il caricamento eager delle proprietà di navigazione Instructor.OfficeAssignment
e Instructor.CourseAssignments
. All'interno della proprietà CourseAssignments
viene caricata la proprietà Course
e all'interno di questa vengono caricate le proprietà Enrollments
e Department
, e all'interno di ogni entità Enrollment
viene caricata la proprietà Student
.
viewModel.Instructors = await _context.Instructors
.Include(i => i.OfficeAssignment)
.Include(i => i.CourseAssignments)
.ThenInclude(i => i.Course)
.ThenInclude(i => i.Enrollments)
.ThenInclude(i => i.Student)
.Include(i => i.CourseAssignments)
.ThenInclude(i => i.Course)
.ThenInclude(i => i.Department)
.AsNoTracking()
.OrderBy(i => i.LastName)
.ToListAsync();
Poiché la vista richiede sempre l'entità OfficeAssignment
, è più efficiente recuperarla nella stessa query. Le entità Course sono necessarie quando viene selezionato un insegnante nella pagina Web. Un'unica query, quindi, è più efficiente di più query solo se nella maggior parte dei casi la pagina viene visualizzata con un corso selezionato.
Il codice ripete CourseAssignments
e Course
perché da Course
sono necessarie due proprietà. La prima stringa delle chiamate ThenInclude
ottiene CourseAssignment.Course
, Course.Enrollments
e Enrollment.Student
.
Altre informazioni sull'inclusione di più livelli di dati correlati sono disponibili qui.
viewModel.Instructors = await _context.Instructors
.Include(i => i.OfficeAssignment)
.Include(i => i.CourseAssignments)
.ThenInclude(i => i.Course)
.ThenInclude(i => i.Enrollments)
.ThenInclude(i => i.Student)
.Include(i => i.CourseAssignments)
.ThenInclude(i => i.Course)
.ThenInclude(i => i.Department)
.AsNoTracking()
.OrderBy(i => i.LastName)
.ToListAsync();
A questo punto nel codice, un'altra chiamata ThenInclude
riguarda le proprietà di navigazione di Student
, che non sono necessarie. Ma chiamando Include
il codice ricomincia con le proprietà di Instructor
. È quindi necessario ripetere la sequenza, questa volta specificando Course.Department
anziché Course.Enrollments
.
viewModel.Instructors = await _context.Instructors
.Include(i => i.OfficeAssignment)
.Include(i => i.CourseAssignments)
.ThenInclude(i => i.Course)
.ThenInclude(i => i.Enrollments)
.ThenInclude(i => i.Student)
.Include(i => i.CourseAssignments)
.ThenInclude(i => i.Course)
.ThenInclude(i => i.Department)
.AsNoTracking()
.OrderBy(i => i.LastName)
.ToListAsync();
Il codice seguente viene eseguito quando è stato selezionato un insegnante. L'insegnante selezionato viene recuperato dall'elenco di insegnanti nel modello di visualizzazione. La proprietà del modello di Courses
visualizzazione viene quindi caricata con le Course
entità dalla proprietà di navigazione dell'insegnante CourseAssignments
.
if (id != null)
{
ViewData["InstructorID"] = id.Value;
Instructor instructor = viewModel.Instructors.Where(
i => i.ID == id.Value).Single();
viewModel.Courses = instructor.CourseAssignments.Select(s => s.Course);
}
Il metodo Where
restituisce una raccolta, ma in questo caso i criteri passati a tale metodo hanno come risultato la restituzione di una sola entità Instructor. Il Single
metodo converte la raccolta in una singola Instructor
entità, che consente di accedere alla proprietà dell'entità CourseAssignments
. La proprietà CourseAssignments
contiene entità CourseAssignment
, di cui si vogliono solo le entità Course
correlate.
Usare il metodo Single
per una raccolta quando si sa che la raccolta ha un solo elemento. Il Single
metodo genera un'eccezione se la raccolta viene passata a essa vuota o se è presente più di un elemento. In alternativa, è possibile usare SingleOrDefault
, che restituisce un valore predefinito (Null in questo caso) se la raccolta è vuota. In questo caso, tuttavia, ciò avrebbe comunque come risultato un'eccezione (a causa del tentativo di cercare una proprietà Courses
in un riferimento Null) e il messaggio di eccezione indicherebbe meno chiaramente la causa del problema. Quando si chiama il metodo Single
, è anche possibile passare la condizione Where anziché chiamare il metodo Where
separatamente:
.Single(i => i.ID == id.Value)
Invece di:
.Where(i => i.ID == id.Value).Single()
Se è stato selezionato un corso, questo viene quindi recuperato dall'elenco dei corsi nel modello di visualizzazione. La proprietà Enrollments
del modello di visualizzazione viene quindi caricata con le entità Enrollment dalla proprietà di navigazione Enrollments
di tale corso.
if (courseID != null)
{
ViewData["CourseID"] = courseID.Value;
viewModel.Enrollments = viewModel.Courses.Where(
x => x.CourseID == courseID).Single().Enrollments;
}
Rilevamento e nessun rilevamento
Le query senza rilevamento sono utili quando i risultati vengono usati in uno scenario di sola lettura. In genere sono più veloci da eseguire perché non è necessario configurare le informazioni sul rilevamento delle modifiche. Se non è necessario aggiornare le entità recuperate dal database, è probabile che una query di rilevamento non funzioni meglio di una query di rilevamento.
In alcuni casi una query di rilevamento è più efficiente di una query senza rilevamento. Per altre informazioni, vedere Tracking vs. No-Tracking Queries.For more information, see Tracking vs. No-Tracking Queries.
Modificare la visualizzazione dell'indice degli insegnanti
In Views/Instructors/Index.cshtml
sostituire il codice del modello con il codice seguente. Le modifiche sono evidenziate.
@model ContosoUniversity.Models.SchoolViewModels.InstructorIndexData
@{
ViewData["Title"] = "Instructors";
}
<h2>Instructors</h2>
<p>
<a asp-action="Create">Create New</a>
</p>
<table class="table">
<thead>
<tr>
<th>Last Name</th>
<th>First Name</th>
<th>Hire Date</th>
<th>Office</th>
<th>Courses</th>
<th></th>
</tr>
</thead>
<tbody>
@foreach (var item in Model.Instructors)
{
string selectedRow = "";
if (item.ID == (int?)ViewData["InstructorID"])
{
selectedRow = "table-success";
}
<tr class="@selectedRow">
<td>
@Html.DisplayFor(modelItem => item.LastName)
</td>
<td>
@Html.DisplayFor(modelItem => item.FirstMidName)
</td>
<td>
@Html.DisplayFor(modelItem => item.HireDate)
</td>
<td>
@if (item.OfficeAssignment != null)
{
@item.OfficeAssignment.Location
}
</td>
<td>
@foreach (var course in item.CourseAssignments)
{
@course.Course.CourseID @course.Course.Title <br />
}
</td>
<td>
<a asp-action="Index" asp-route-id="@item.ID">Select</a> |
<a asp-action="Edit" asp-route-id="@item.ID">Edit</a> |
<a asp-action="Details" asp-route-id="@item.ID">Details</a> |
<a asp-action="Delete" asp-route-id="@item.ID">Delete</a>
</td>
</tr>
}
</tbody>
</table>
@model ContosoUniversity.Models.SchoolViewModels.InstructorIndexData
@{
ViewData["Title"] = "Instructors";
}
<h2>Instructors</h2>
<p>
<a asp-action="Create">Create New</a>
</p>
<table class="table">
<thead>
<tr>
<th>Last Name</th>
<th>First Name</th>
<th>Hire Date</th>
<th>Office</th>
<th>Courses</th>
<th></th>
</tr>
</thead>
<tbody>
@foreach (var item in Model.Instructors)
{
string selectedRow = "";
if (item.ID == (int?)ViewData["InstructorID"])
{
selectedRow = "success";
}
<tr class="@selectedRow">
<td>
@Html.DisplayFor(modelItem => item.LastName)
</td>
<td>
@Html.DisplayFor(modelItem => item.FirstMidName)
</td>
<td>
@Html.DisplayFor(modelItem => item.HireDate)
</td>
<td>
@if (item.OfficeAssignment != null)
{
@item.OfficeAssignment.Location
}
</td>
<td>
@foreach (var course in item.CourseAssignments)
{
@course.Course.CourseID @course.Course.Title <br />
}
</td>
<td>
<a asp-action="Index" asp-route-id="@item.ID">Select</a> |
<a asp-action="Edit" asp-route-id="@item.ID">Edit</a> |
<a asp-action="Details" asp-route-id="@item.ID">Details</a> |
<a asp-action="Delete" asp-route-id="@item.ID">Delete</a>
</td>
</tr>
}
</tbody>
</table>
Al codice esistente sono state apportate le modifiche seguenti:
La classe del modello è stata modificata in
InstructorIndexData
.Il titolo pagina è stato modificato da Index (Indice) a Instructors (Insegnanti).
È stata aggiunta la colonna Office (Ufficio) che visualizza
item.OfficeAssignment.Location
solo seitem.OfficeAssignment
non è Null. Poiché questa è una relazione uno-a-zero-o-uno, potrebbe non esserci un'entità OfficeAssignment correlata.@if (item.OfficeAssignment != null) { @item.OfficeAssignment.Location }
È stata aggiunta la colonna Courses (Corsi) che visualizza i corsi tenuti da ogni insegnante. Per altre informazioni, vedere la sezione Transizione di riga esplicita dell'articolo sulla Razor sintassi.
Aggiunta del codice che aggiunge in modo condizionale una classe CSS Bootstrap all'elemento dell'insegnante
tr
selezionato. Questa classe imposta un colore di sfondo per la riga selezionata.È stato aggiunto un nuovo collegamento ipertestuale con etichetta Select (Seleziona) immediatamente prima degli altri collegamenti in ogni riga.Ciò comporta l'invio dell'ID dell'insegnante selezionato al metodo
Index
.<a asp-action="Index" asp-route-id="@item.ID">Select</a> |
Eseguire l'app e selezionare la scheda Instructors (Insegnanti). Nella pagina viene visualizzata la proprietà Location delle entità OfficeAssignment correlate e una cella di tabella vuota quando non è presente alcuna entità OfficeAssignment correlata.
Views/Instructors/Index.cshtml
Nel file, dopo l'elemento della tabella di chiusura (alla fine del file), aggiungere il codice seguente. Quando è selezionato un insegnante, Questo codice visualizza un elenco dei corsi correlati all'insegnante stesso.
@if (Model.Courses != null)
{
<h3>Courses Taught by Selected Instructor</h3>
<table class="table">
<tr>
<th></th>
<th>Number</th>
<th>Title</th>
<th>Department</th>
</tr>
@foreach (var item in Model.Courses)
{
string selectedRow = "";
if (item.CourseID == (int?)ViewData["CourseID"])
{
selectedRow = "success";
}
<tr class="@selectedRow">
<td>
@Html.ActionLink("Select", "Index", new { courseID = item.CourseID })
</td>
<td>
@item.CourseID
</td>
<td>
@item.Title
</td>
<td>
@item.Department.Name
</td>
</tr>
}
</table>
}
Questo codice legge la proprietà Courses
del modello di visualizzazione per visualizzare l'elenco dei corsi. Fornisce anche il collegamento ipertestuale Select (Seleziona) che invia l'ID del corso selezionato al metodo di azione Index
.
Aggiornare la pagina e selezionare un insegnante. È ora possibile vedere una griglia con i corsi assegnati all'insegnante selezionato. Per ogni corso è possibile vedere il nome del dipartimento assegnato.
Dopo il blocco di codice appena aggiunto, aggiungere il codice seguente. Quando è selezionato un corso, questo codice visualizza l'elenco degli studenti iscritti al corso selezionato.
@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>
}
Questo codice legge la Enrollments
proprietà del modello di visualizzazione per visualizzare un elenco di studenti iscritti al corso.
Aggiornare di nuovo la pagina e selezionare un insegnante. Selezionare quindi un corso per visualizzare l'elenco degli studenti iscritti e i voti corrispondenti.
Informazioni sul caricamento esplicito
Quando è stato recuperato l'elenco di istruttori in InstructorsController.cs
, è stato specificato il caricamento eager per la CourseAssignments
proprietà di navigazione.
Si supponga che gli utenti vogliano visualizzare solo raramente le iscrizioni per un corso e un insegnante selezionati. In tal caso, è consigliabile caricare i dati delle iscrizioni solo se richiesti. Per un esempio di come eseguire il caricamento esplicito, sostituire il Index
metodo con il codice seguente, che rimuove il caricamento eager per Enrollments
e carica tale proprietà in modo esplicito. Le modifiche al codice sono evidenziate.
public async Task<IActionResult> Index(int? id, int? courseID)
{
var viewModel = new InstructorIndexData();
viewModel.Instructors = await _context.Instructors
.Include(i => i.OfficeAssignment)
.Include(i => i.CourseAssignments)
.ThenInclude(i => i.Course)
.ThenInclude(i => i.Department)
.OrderBy(i => i.LastName)
.ToListAsync();
if (id != null)
{
ViewData["InstructorID"] = id.Value;
Instructor instructor = viewModel.Instructors.Where(
i => i.ID == id.Value).Single();
viewModel.Courses = instructor.CourseAssignments.Select(s => s.Course);
}
if (courseID != null)
{
ViewData["CourseID"] = courseID.Value;
var selectedCourse = viewModel.Courses.Where(x => x.CourseID == courseID).Single();
await _context.Entry(selectedCourse).Collection(x => x.Enrollments).LoadAsync();
foreach (Enrollment enrollment in selectedCourse.Enrollments)
{
await _context.Entry(enrollment).Reference(x => x.Student).LoadAsync();
}
viewModel.Enrollments = selectedCourse.Enrollments;
}
return View(viewModel);
}
Il nuovo codice elimina le chiamate al ThenInclude
metodo per i dati di registrazione dal codice che recupera le entità dell'insegnante. Elimina anche AsNoTracking
. Se viene selezionato un insegnante e un corso, il codice evidenziato recupera Enrollment
le entità per il corso selezionato e Student
le entità per ogni Enrollment
oggetto .
Eseguire l'app e passare alla pagina di indice degli insegnanti. Non si noterà alcuna differenza in ciò che viene visualizzato nella pagina, anche se è stata modificata la modalità di recupero dei dati.
Ottenere il codice
Scaricare o visualizzare l'applicazione completata.
Passaggi successivi
In questa esercitazione:
- Come caricare i dati correlati
- Creazione di una pagina Courses
- Creazione di una pagina Instructors
- Raccolta di informazioni sul caricamento esplicito
Passare all'esercitazione successiva per informazioni su come aggiornare i dati correlati.