Condividi tramite


Lettura di dati correlati con Entity Framework in un'applicazione MVC di ASP.NET (5 di 10)

di Tom Dykstra

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

Nota

Se si verifica un problema che non è possibile risolvere, scaricare il capitolo completato e provare a riprodurre il problema. In genere è possibile trovare la soluzione al problema confrontando il codice con il codice completato. Per alcuni errori comuni e come risolverli, vedere Errori e soluzioni alternative.

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

Le figure seguenti illustrano le pagine che verranno usate.

Screenshot che mostra la pagina Indice corsi di Contoso University.

Screenshot che mostra la pagina Indice docenti Contoso University con un insegnante e uno dei corsi selezionati.

Esistono diversi modi in cui Entity Framework può caricare i dati correlati nelle proprietà di spostamento 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 i dati correlati per l'entità devono essere recuperati.

    Lazy_loading_example

  • Caricamento ansioso. 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 ansioso usando il Include metodo .

    Eager_loading_example

  • Caricamento esplicito. Questo è simile al caricamento lazy, ad eccezione del fatto che i dati correlati vengano recuperati in modo esplicito nel codice; non avviene automaticamente quando si accede a una proprietà di spostamento. I dati correlati vengono caricati manualmente recuperando la voce gestione stati oggetti per un'entità e chiamando il metodo per le raccolte o il Collection.LoadReference.Load metodo per le proprietà che contengono una singola entità. Nell'esempio seguente, se si vuole caricare la proprietà di spostamento Amministratore, sostituire Collection(x => x.Courses) con Reference(x => x.Administrator).)

    Explicit_loading_example

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

In generale, se si sa che sono necessari dati correlati per ogni entità recuperata, il caricamento ansioso offre le prestazioni migliori, perché una singola query inviata al database è in genere più efficiente rispetto alle query separate per ogni entità recuperata. Ad esempio, negli esempi precedenti si supponga che ogni reparto abbia dieci corsi correlati. L'esempio di caricamento ansioso comporta solo una singola query (join) e un singolo round trip nel database. Gli esempi di caricamento e caricamento esplicito lazy comportano sia undici query che undici round trip nel 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 lazy è più efficiente. Il caricamento ansioso potrebbe causare la generazione di un join molto complesso, che SQL Server non può elaborare in modo efficiente. Oppure se è necessario accedere alle proprietà di spostamento di un'entità solo per un subset di un set di entità che si sta elaborando, il caricamento lazy potrebbe risultare migliore perché il caricamento ansioso recupera più dati che 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.

In genere si userà il caricamento esplicito solo quando è stato disattivato il caricamento lazy. Uno scenario quando è necessario disattivare il caricamento lazy è durante la serializzazione. Il caricamento e la serializzazione lazy non si combinano bene e, se non si è attenti, è possibile eseguire query in modo significativo su più dati rispetto a quelli previsti quando è abilitato il caricamento lazy. La serializzazione funziona in genere accedendo a ogni proprietà in un'istanza di un tipo. L'accesso alle proprietà attiva il caricamento in ritardo e quelle entità caricate in ritardo vengono serializzate. Il processo di serializzazione accede quindi a ogni proprietà delle entità caricate con lazy, causando potenzialmente un caricamento e una serializzazione ancora più lazy. Per evitare questa reazione a catena di run-away, disattivare il caricamento lazy prima di serializzare un'entità.

La classe di contesto del database esegue il caricamento lazy per impostazione predefinita. Esistono due modi per disabilitare il caricamento lazy:

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

  • Per tutte le proprietà di spostamento, impostare LazyLoadingEnabled su false. Ad esempio, è possibile inserire il codice seguente nel costruttore della classe di contesto:

    this.Configuration.LazyLoadingEnabled = false;
    

Il caricamento lazy può mascherare il codice che causa problemi di prestazioni. Ad esempio, il codice che non specifica caricamento ansioso o esplicito, ma elabora un volume elevato di entità e usa diverse proprietà di spostamento in ogni iterazione potrebbe essere molto inefficiente (a causa di molti round trip nel database). Un'applicazione che esegue correttamente lo sviluppo usando un server SQL locale potrebbe avere problemi di prestazioni quando viene spostata in Azure SQL Database a causa dell'aumento della latenza e del caricamento in ritardo. La profilatura delle query di database con un carico di test realistico consente di determinare se il caricamento in ritardo è appropriato. Per altre informazioni, vedere Demystifying Entity Framework Strategies: Caricamento di dati correlati e uso di Entity Framework per ridurre la latenza di rete in SQL Azure.

Creare una pagina indice corsi che visualizza il nome del reparto

L'entità Course include una proprietà di navigazione che contiene l'entità Department del reparto a cui viene assegnato il corso. Per visualizzare il nome del reparto assegnato in un elenco di corsi, è necessario ottenere la Name proprietà dall'entità Department presente nella Course.Department proprietà di spostamento.

Creare un controller denominato CourseController per il Course tipo di entità, usando le stesse opzioni precedenti per il Student controller, come illustrato nella figura seguente (ad eccezione dell'immagine, la classe di contesto si trova nello spazio dei nomi DAL, non nello spazio dei nomi Modelli):

Add_Controller_dialog_box_for_Course_controller

Aprire Controller\CourseController.cs e esaminare il Index metodo:

public ViewResult 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 esistente 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>
    <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>

Al codice con scaffolding sono state apportate le modifiche seguenti:

  • Modifica l'intestazione da Indice a Corsi.
  • Spostato i collegamenti di riga a sinistra.
  • Aggiunta di una colonna nel titolo Numero che mostra il valore della CourseID proprietà. Per impostazione predefinita, le chiavi primarie non vengono scaffolded perché normalmente sono senza significato agli utenti finali. Tuttavia, in questo caso la chiave primaria è significativa e si vuole visualizzarla.
  • Modifica l'ultima intestazione di colonna da DepartmentID (nome della chiave esterna all'entità Department ) in Reparto.

Si noti che per l'ultima colonna, il codice scaffolded 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 nomi di reparto.

Courses_index_page_with_department_names

Creare una pagina indice docente che mostra corsi e registrazioni

In questa sezione si creerà un controller e una visualizzazione per l'entità per visualizzare la pagina Dell'indice Instructor instructors:

Screenshot che mostra la pagina Indice insegnanti con un insegnante e uno dei corsi selezionati.

Questa pagina legge e visualizza dati correlati nei modi seguenti:

  • L'elenco degli insegnanti visualizza i dati correlati dall'entità OfficeAssignment . Tra le entità Instructor e OfficeAssignment c'è una relazione uno-a-zero-o-uno. Si userà il caricamento ansioso 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 ansioso per le entità e le Course relative entità correlate Department . In questo caso, il caricamento lazy 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 le entità e le Enrollment relative entità correlate Student . Il caricamento esplicito non è necessario perché il caricamento lazy è abilitato, ma illustra come eseguire il caricamento esplicito.

Creare un modello di visualizzazione per la visualizzazione indice di istruttore

La pagina Indice istruttore 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; }
    }
}

Aggiunta di uno stile per le righe selezionate

Per contrassegnare le righe selezionate è necessario un colore di sfondo diverso. Per fornire uno stile per questa interfaccia utente, aggiungere il codice evidenziato seguente alla sezione /* info and errors */ contenuto \Site.css, come illustrato di seguito:

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

Creazione del controller e delle visualizzazioni dell'insegnante

Creare un InstructorController controller come illustrato nella figura seguente:

Add_Controller_dialog_box_for_Instructor_controller

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

using ContosoUniversity.ViewModels;

Il codice scaffolded nel Index metodo specifica il caricamento ansioso solo per la proprietà di OfficeAssignment navigazione:

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

Sostituire il metodo con il Index 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.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);
}

Il metodo accetta dati di route facoltativi () e un parametro stringa di query (idcourseID) che specificano 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.

Suggerimento

Indirizzare i dati

I dati di route sono dati che il binding del modello trovato in un segmento DI URL specificato nella tabella di routing. Ad esempio, la route predefinita specifica controller, e actionid segmenti:

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

Nell'URL seguente la route predefinita viene mappata Instructor come , Index come actioncontrollere 1 come id. Questi sono valori di dati di route.

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

"?courseID=2021" è un valore stringa di query. Il binder del modello funzionerà anche se si passa come id valore stringa di query:

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

Gli URL vengono creati dalle ActionLink istruzioni nella visualizzazione Razor. Nel codice seguente il id parametro corrisponde alla route predefinita, quindi id viene aggiunto ai dati della route.

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

Nel codice seguente non courseID corrisponde a un parametro nella route predefinita, quindi viene aggiunto come stringa di query.

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

Il codice inizia creando un'istanza del modello di visualizzazione e inserendola nell'elenco degli insegnanti. Il codice specifica il caricamento per l'oggetto Instructor.OfficeAssignment e la proprietà di Instructor.Courses spostamento.

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 i corsi e per ogni corso caricato esegue il caricamento per la proprietà di Course.Department navigazione.

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

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

Se è stato selezionato un ID insegnante, l'insegnante selezionato viene recuperato dall'elenco degli 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 Courses .

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

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

Si usa il metodo Single in una raccolta quando si sa che l'insieme 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. Tuttavia, in questo caso, ciò comporta comunque un'eccezione (dal tentativo di trovare una Courses proprietà su un null riferimento) e il messaggio di eccezione indica in modo meno chiaro 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.InstructorID == id.Value)

Anziché:

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

Se è stato selezionato un corso, questo viene quindi recuperato dall'elenco dei corsi nel modello di visualizzazione. La proprietà del Enrollments modello di visualizzazione viene quindi caricata con le Enrollment entità dalla proprietà di spostamento del Enrollments corso.

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

Modifica della visualizzazione indice dell'istruttore

In Views\Instructor\Index.cshtml sostituire il codice esistente 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> 
    <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>

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

  • Spostate le colonne di collegamento di riga a sinistra.

  • Rimossa la colonna FullName .

  • Aggiunta di una colonna di Office che visualizza 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>
    
  • Aggiunto codice che aggiungerà class="selectedrow" dinamicamente all'elemento dell'insegnante tr selezionato. Questo imposta un colore di sfondo per la riga selezionata usando la classe CSS creata in precedenza. L'attributo valign sarà utile nell'esercitazione seguente quando si aggiunge una colonna a più righe alla tabella.

    string selectedRow = ""; 
    if (item.InstructorID == ViewBag.InstructorID) 
    { 
        selectedRow = "selectedrow"; 
    } 
    <tr class="@selectedRow" valign="top">
    
  • Aggiunta di una nuova ActionLink etichetta Seleziona immediatamente prima degli altri collegamenti in ogni riga, che causa l'invio dell'ID dell'insegnante Index selezionato al metodo.

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

Instructors_index_page_with_nothing_selected

Nel file Views\Instructor\Index.cshtml , dopo l'elemento di chiusura table (alla fine del file), aggiungere il codice evidenziato seguente. In questo modo viene visualizzato un elenco di corsi correlati a un insegnante quando viene selezionato un insegnante.

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

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

Nota

Il file CSS viene memorizzato nella cache dai browser. Se non vengono visualizzate le modifiche quando si esegue l'applicazione, eseguire un aggiornamento rigido (tenere premuto il tasto CTRL mentre si fa clic sul pulsante Aggiorna o premere CTRL+F5).

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.

Instructors_index_page_with_instructor_selected

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> 
        <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 registrati nel corso.

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

Screenshot della pagina Indice insegnanti con un insegnante e uno dei loro corsi selezionati.

Aggiunta del caricamento esplicito

Aprire InstructorController.cs e esaminare come il metodo ottiene l'elenco Index 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 desiderato per la proprietà di navigazione e per la CoursesDepartment proprietà di ogni corso. Quindi si inserisce la Courses raccolta nel modello di visualizzazione e si accede alla Enrollments proprietà di spostamento da un'entità nella raccolta. Poiché non è stato specificato il caricamento ansioso per la Course.Enrollments proprietà di spostamento, i dati di tale proprietà vengono visualizzati nella pagina in seguito al caricamento in ritardo.

Se il caricamento lazy è stato disabilitato senza modificare il codice in qualsiasi 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 o il caricamento esplicito. Hai già visto come eseguire il caricamento ansioso. Per visualizzare un esempio di caricamento esplicito, sostituire il metodo con il Index 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.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);
}

Dopo aver ottenuto l'entità selezionata Course , il nuovo codice carica in modo esplicito la proprietà di spostamento 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 solo un'entità, si usa il Reference metodo . È possibile eseguire la pagina Indice dell'istruttore ora e non si noterà alcuna differenza nella pagina, anche se i dati vengono recuperati.

Riepilogo

Sono stati ora usati tutti e tre i modi (lazy, ansioso e esplicito) per caricare i dati correlati nelle proprietà di spostamento. Nella prossima esercitazione si apprenderà come aggiornare i dati correlati.

I collegamenti ad altre risorse di Entity Framework sono disponibili nella mappa del contenuto di accesso ai dati ASP.NET.