Esercitazione: Leggere i dati correlati con Entity Framework in un'app MVC ASP.NET

Nell'esercitazione precedente è stato completato il modello di dati School. In questa esercitazione verranno letti e visualizzati i dati correlati, ovvero i dati caricati da Entity Framework nelle proprietà di navigazione.

Le figure seguenti illustrano le pagine che verranno usate.

Screenshot che mostra la pagina Corsi con un elenco di corsi.

Instructors_index_page_with_instructor_and_course_selected

Scaricare il progetto completato

L'applicazione Web di esempio Contoso University illustra come creare ASP.NET applicazioni MVC 5 usando Entity Framework 6 Code First e Visual Studio. Per informazioni sulla serie di esercitazioni, vedere la prima esercitazione della serie.

In questa esercitazione:

  • Scoprire come caricare i dati correlati
  • Creare una pagina Courses
  • Creare una pagina Instructors

Prerequisiti

Esistono diversi modi in cui Entity Framework può caricare i dati correlati nelle proprietà di navigazione di un'entità:

  • Caricamento lazy. Quando un'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. Ciò comporta più query inviate al database, una per l'entità stessa e una ogni volta che devono essere recuperati i dati correlati per l'entità. La DbContext classe abilita il caricamento differita per impostazione predefinita.

    Lazy_loading_example

  • Caricamento eager. Quando l'entità viene letta, i dati correlati corrispondenti vengono recuperati insieme ad essa. Ciò in genere ha come risultato una query join singola che recupera tutti i dati necessari. Specificare il caricamento eager usando il Include metodo .

    Eager_loading_example

  • Caricamento esplicito È simile al caricamento differita, ad eccezione del fatto che si recuperano in modo esplicito i dati correlati nel codice; non si verifica automaticamente quando si accede a una proprietà di navigazione. I dati correlati vengono caricati manualmente recuperando la voce di gestione dello stato dell'oggetto per un'entità e chiamando il metodo Collection.Load per le raccolte o il metodo Reference.Load per le proprietà che contengono una singola entità. Nell'esempio seguente, se si vuole caricare la proprietà di navigazione Administrator, sostituire Collection(x => x.Courses) con Reference(x => x.Administrator).) In genere si usa il caricamento esplicito solo quando il caricamento differita è stato disattivato.

    Explicit_loading_example

Poiché non recuperano immediatamente i valori delle proprietà, il caricamento differito e il caricamento esplicito sono noti anche come caricamento posticipato.

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. Ad esempio, negli esempi precedenti, si supponga che ogni reparto abbia dieci corsi correlati. L'esempio di caricamento eager genera solo una singola query (join) e un singolo round trip al database. Gli esempi di caricamento differita ed esplicito comportano sia undici query che 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 il caricamento differita è più efficiente. Il caricamento eager potrebbe causare la generazione di un join molto complesso, che SQL Server non può elaborare in modo efficiente. In alternativa, se è necessario accedere alle proprietà di navigazione di un'entità solo per un subset di un set di entità elaborate, il caricamento differita potrebbe risultare migliore perché il caricamento eager recupererebbe più dati di quanto necessario. 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.

Il caricamento differita può mascherare il codice che causa problemi di prestazioni. Ad esempio, il codice che non specifica il caricamento eager o esplicito, ma elabora un volume elevato di entità e usa diverse proprietà di navigazione in ogni iterazione potrebbe essere molto inefficiente (a causa di molti round trip al database). Un'applicazione con prestazioni ottimali nello sviluppo che usa un server SQL locale potrebbe avere problemi di prestazioni quando viene spostata in database SQL di Azure a causa dell'aumento della latenza e del caricamento differita. La profilatura delle query di database con un carico di test realistico consente di determinare se il caricamento differita è appropriato. Per altre informazioni, vedere Demystifying Entity Framework Strategies: Loading Related Data and Using the Entity Framework to Reduce Network Latency to SQL Azure .For more information see Demystifying Entity Framework Strategies: Loading Related Data and Using the Entity Framework to Reduce Network Latency to SQL Azure.

Disabilitare il caricamento differita prima della serializzazione

Se si lascia il caricamento differita abilitato durante la serializzazione, è possibile eseguire query su più dati rispetto a quanto previsto. La serializzazione funziona in genere accedendo a ogni proprietà in un'istanza di un tipo. L'accesso alle proprietà attiva il caricamento differita e le entità caricate lazy vengono serializzate. Il processo di serializzazione accede quindi a ogni proprietà delle entità con caricamento differita, causando potenzialmente un caricamento e una serializzazione ancora più differita. Per evitare questa reazione a catena di fuga, disattivare il caricamento differita prima di serializzare un'entità.

La serializzazione può anche essere complicata dalle classi proxy usate da Entity Framework, come illustrato nell'esercitazione Scenari avanzati.

Un modo per evitare problemi di serializzazione consiste nel serializzare oggetti di trasferimento dati (DTO) anziché oggetti entità, come illustrato nell'esercitazione Uso dell'API Web con Entity Framework .

Se non si usano DTO, è possibile disabilitare il caricamento differita ed evitare problemi proxy disabilitando la creazione del proxy.

Ecco alcuni altri modi per disabilitare il caricamento differita:

  • Per proprietà di navigazione specifiche, omettere la virtual parola chiave quando si dichiara la proprietà .

  • Per tutte le proprietà di navigazione, impostare su LazyLoadingEnabled false, inserire il codice seguente nel costruttore della classe di contesto:

    this.Configuration.LazyLoadingEnabled = false;
    

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 CourseController (non CoursesController) per il Course tipo di entità, usando le stesse opzioni per il controller MVC 5 con visualizzazioni, usando lo scaffolder di Entity Framework eseguito in precedenza per il Student controller:

Impostazione Valore
Classe modello Selezionare Course (ContosoUniversity.Models).
Classe contesto dati Selezionare SchoolContext (ContosoUniversity.DAL).
Nome controller Immettere CourseController. Anche in questo caso, non CoursesController con una s. Quando è stato selezionato Course (ContosoUniversity.Models), il valore del nome controller è stato popolato automaticamente. È necessario modificare il valore.

Lasciare gli altri valori predefiniti e aggiungere il controller.

Aprire Controllers\CourseController.cs ed esaminare il Index metodo :

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

Lo scaffolding automatico ha specificato il caricamento eager per la proprietà di navigazione Department tramite il metodo Include.

Aprire Views\Course\Index.cshtml e sostituire il codice del modello con il codice seguente. Le modifiche sono evidenziate:

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

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, le chiavi primarie non vengono scaffolding perché in genere sono senza significato per gli utenti finali. In questo caso, tuttavia, la chiave primaria è significativa ed è necessario visualizzarla.
  • Spostare la colonna Reparto sul lato destro e modificarne l'intestazione. Lo scaffolder ha scelto correttamente di visualizzare la Name proprietà dall'entità Department , ma qui nella pagina Course l'intestazione di colonna deve essere Department anziché Name.

Si noti che per la colonna Reparto, il codice con scaffolding visualizza la Name proprietà dell'entità Department caricata nella Department proprietà di navigazione:

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

Eseguire la pagina (selezionare la scheda Corsi nella home page di Contoso University) per visualizzare l'elenco con i nomi dei reparti.

Creare una pagina Instructors

In questa sezione si creerà un controller e si visualizzerà l'entità Instructor per visualizzare la pagina Instructors . 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 e OfficeAssignment c'è una relazione uno-a-zero-o-uno. Si userà il caricamento eager per le OfficeAssignment 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 e Course esiste una relazione molti-a-molti. Si userà il caricamento eager per le Course entità e le relative entità correlate Department . In questo caso, il caricamento differita potrebbe essere più efficiente perché sono necessari corsi 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 e Enrollment esiste una relazione uno-a-molti. Si aggiungerà il caricamento esplicito per Enrollment le entità e le relative entità correlate Student . Il caricamento esplicito non è necessario perché il caricamento differita è abilitato, ma viene illustrato come eseguire il caricamento esplicito.

Creare un modello di visualizzazione per la visualizzazione indice instructor

La pagina Instructors (Insegnanti) mostra tre tabelle diverse. Verrà quindi creato un modello di visualizzazione che includa tre proprietà, ognuna contenente i dati di una delle tabelle.

Nella cartella ViewModels creare InstructorIndexData.cs e sostituire il codice esistente con il codice seguente:

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

Creare il controller e le visualizzazioni dell'insegnante

Creare un InstructorController controller (non InstructorsController) con l'azione di lettura/scrittura di ENTITY:

Impostazione Valore
Classe modello Selezionare Instructor (ContosoUniversity.Models).
Classe contesto dati Selezionare SchoolContext (ContosoUniversity.DAL).
Nome controller Immettere InstructorController. Anche in questo caso, non InstructorsController con una s. Quando è stato selezionato Course (ContosoUniversity.Models), il valore del nome controller è stato popolato automaticamente. È necessario modificare il valore.

Lasciare gli altri valori predefiniti e aggiungere il controller.

Aprire Controllers\InstructorController.cs e aggiungere un'istruzione using per lo spazio dei ViewModels nomi:

using ContosoUniversity.ViewModels;

Il codice con scaffolding nel Index metodo specifica il caricamento eager solo per la proprietà di OfficeAssignment navigazione:

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

Sostituire il Index metodo con il codice seguente per caricare dati correlati aggiuntivi e inserirli nel modello di visualizzazione:

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

Il metodo accetta dati di route facoltativi () e un parametro stringa di query (idcourseID) che forniscono i valori ID dell'insegnante selezionato e del corso selezionato e passa tutti i dati necessari alla visualizzazione. 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 per e Instructor.OfficeAssignment la proprietà di Instructor.Courses navigazione.

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

Il secondo Include metodo carica Courses e per ogni Course caricato esegue il caricamento eager per la proprietà di Course.Department navigazione.

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

Come accennato in precedenza, il caricamento eager non è necessario, ma viene eseguito per migliorare le prestazioni. Poiché la vista richiede sempre l'entità OfficeAssignment , è più efficiente recuperarla nella stessa query. Course le entità sono necessarie quando un insegnante viene selezionato nella pagina Web, quindi il caricamento eager è migliore del caricamento differita solo se la pagina viene visualizzata più spesso con un corso selezionato rispetto a senza.

Se è stato selezionato un ID docente, l'insegnante selezionato viene recuperato dall'elenco di istruttori nel modello di visualizzazione. La proprietà del modello di Courses visualizzazione viene quindi caricata con le Course entità dalla proprietà di navigazione dell'insegnante Courses .

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

Il Where metodo restituisce una raccolta, ma in questo caso i criteri passati a tale metodo comportano la restituzione di una sola Instructor entità. Il Single metodo converte la raccolta in una singola Instructor entità, che consente di accedere alla proprietà dell'entità Courses .

Utilizzare il metodo Single in una raccolta quando si sa che la raccolta avrà un solo elemento. Il Single metodo genera un'eccezione se la raccolta passata è vuota o se è presente più di un elemento. Un'alternativa è SingleOrDefault, che restituisce un valore predefinito (null in questo caso) se la raccolta è vuota. In questo caso, tuttavia, si verificherebbe comunque un'eccezione (dal tentativo di trovare una Courses proprietà su un null riferimento) e il messaggio di eccezione indicherà meno chiaramente la causa del problema. Quando si chiama il Single metodo , è anche possibile passare la Where condizione anziché chiamare il Where metodo separatamente:

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

Anziché:

.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à del modello di Enrollments visualizzazione viene quindi caricata con le Enrollment entità della proprietà di navigazione del Enrollments corso.

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

Modificare la visualizzazione indice instructor

In Views\Instructor\Index.cshtml sostituire il codice del modello con il codice seguente. Le modifiche sono evidenziate:

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

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).

  • Aggiunta di una colonna di Office che viene visualizzata item.OfficeAssignment.Location solo se item.OfficeAssignment non è Null. Poiché si tratta di una relazione uno-a-zero-o-uno, potrebbe non esserci un'entità correlata OfficeAssignment .

    <td> 
        @if (item.OfficeAssignment != null) 
        { 
            @item.OfficeAssignment.Location  
        } 
    </td>
    
  • Aggiunta del codice che aggiungerà class="success" dinamicamente all'elemento dell'insegnante tr selezionato. In questo modo viene impostato un colore di sfondo per la riga selezionata tramite una classe Bootstrap.

    string selectedRow = ""; 
    if (item.InstructorID == ViewBag.InstructorID) 
    { 
        selectedRow = "success"; 
    } 
    <tr class="@selectedRow" valign="top">
    
  • Aggiunta di una nuova ActionLink etichetta Select immediatamente prima degli altri collegamenti in ogni riga, che fa sì che l'ID docente selezionato venga inviato al Index metodo .

Eseguire l'applicazione e selezionare la scheda Instructors (Insegnanti). La pagina visualizza la Location proprietà delle entità correlate OfficeAssignment e una cella di tabella vuota quando non è presente alcuna entità correlata OfficeAssignment .

Nel file Views\Instructor\Index.cshtml, dopo l'elemento di chiusura table (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 == 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>
}

Questo codice legge la proprietà Courses del modello di visualizzazione per visualizzare l'elenco dei corsi. Fornisce inoltre un Select collegamento ipertestuale che invia l'ID del corso selezionato al Index metodo di azione.

Eseguire 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.

Eseguire la pagina e selezionare un insegnante. Selezionare quindi un corso per visualizzare l'elenco degli studenti iscritti e i voti corrispondenti.

Aggiunta del caricamento esplicito

Aprire InstructorController.cs e osservare come il Index metodo ottiene l'elenco delle registrazioni per un corso selezionato:

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

Quando hai recuperato l'elenco degli insegnanti, hai specificato il caricamento eager per la Courses proprietà di navigazione e per la Department proprietà di ogni corso. Inserire quindi la Courses raccolta nel modello di visualizzazione e ora si accede alla Enrollments proprietà di navigazione da un'entità in tale raccolta. Poiché non è stato specificato il caricamento eager per la Course.Enrollments proprietà di navigazione, i dati di tale proprietà vengono visualizzati nella pagina in seguito al caricamento differita.

Se il caricamento differita è stato disabilitato senza modificare il codice in altro modo, la Enrollments proprietà sarà null indipendentemente dal numero di registrazioni effettivamente presenti nel corso. In tal caso, per caricare la Enrollments proprietà, è necessario specificare il caricamento eager o il caricamento esplicito. Si è già visto come eseguire il caricamento eager. Per visualizzare un esempio di caricamento esplicito, sostituire il Index metodo con il codice seguente, che carica in modo esplicito la Enrollments proprietà. Il codice modificato è evidenziato.

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

Dopo aver ottenuto l'entità selezionata Course , il nuovo codice carica in modo esplicito la proprietà di navigazione del Enrollments corso:

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

Carica quindi in modo esplicito l'entità correlata Student di ogni Enrollment entità:

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

Si noti che si usa il Collection metodo per caricare una proprietà di raccolta, ma per una proprietà che contiene una sola entità, si usa il Reference metodo .

Eseguire la pagina Instructor Index ora e non si noterà alcuna differenza in ciò che viene visualizzato nella pagina, anche se è stato modificato il modo in cui vengono recuperati i dati.

Ottenere il codice

Scaricare il progetto completato

Risorse aggiuntive

I collegamenti ad altre risorse di Entity Framework sono disponibili in ASP.NET Accesso ai dati - Risorse consigliate.

Passaggi successivi

In questa esercitazione:

  • Come caricare i dati correlati
  • Creazione di una pagina Courses
  • Creazione di una pagina Instructors

Passare all'articolo successivo per informazioni su come aggiornare i dati correlati.