Partager via


Lecture des données associées avec Entity Framework dans une application MVC ASP.NET (5 sur 10)

par Tom Dykstra

L’exemple d’application web Contoso University montre comment créer ASP.NET applications MVC 4 à l’aide d’Entity Framework 5 Code First et de Visual Studio 2012. Pour obtenir des informations sur la série de didacticiels, consultez le premier didacticiel de la série.

Notes

Si vous rencontrez un problème que vous ne pouvez pas résoudre, téléchargez le chapitre terminé et essayez de le reproduire. Vous pouvez généralement trouver la solution au problème en comparant votre code au code terminé. Pour connaître certaines erreurs courantes et la façon de les résoudre, consultez Erreurs et solutions de contournement.

Dans le tutoriel précédent, vous avez terminé le modèle de données Scolaire. Dans ce tutoriel, vous allez lire et afficher des données associées, c’est-à-dire des données que Entity Framework charge dans des propriétés de navigation.

Les illustrations suivantes montrent les pages que vous allez utiliser.

Capture d’écran montrant la page Contoso University Courses Index.

Capture d’écran montrant la page Contoso University Instructors Index avec un instructeur et l’un de ses cours sélectionnés.

Il existe plusieurs façons pour Entity Framework de charger des données associées dans les propriétés de navigation d’une entité :

  • Chargement différé. Quand l’entité est lue pour la première fois, les données associées ne sont pas récupérées. Toutefois, la première fois que vous essayez d’accéder à une propriété de navigation, les données requises pour cette propriété de navigation sont récupérées automatiquement. Cela entraîne l’envoi de plusieurs requêtes à la base de données : une pour l’entité elle-même et une à chaque fois que les données associées pour l’entité doivent être récupérées.

    Lazy_loading_example

  • Chargement hâtif. Quand l’entité est lue, ses données associées sont également récupérées. Cela génère en général une requête de jointure unique qui récupère toutes les données nécessaires. Vous spécifiez un chargement pressé à l’aide de la Include méthode .

    Eager_loading_example

  • Chargement explicite. Cela est similaire au chargement paresseux, sauf que vous récupérez explicitement les données associées dans le code ; cela ne se produit pas automatiquement lorsque vous accédez à une propriété de navigation. Vous chargez manuellement les données associées en obtenant l’entrée du gestionnaire d’état d’objet pour une entité et en appelant la Collection.Load méthode pour les collections ou la méthode pour les Reference.Load propriétés qui contiennent une seule entité. (Dans l’exemple suivant, si vous souhaitez charger la propriété de navigation Administrateur, remplacez par Collection(x => x.Courses)Reference(x => x.Administrator).)

    Explicit_loading_example

Étant donné qu’ils ne récupèrent pas immédiatement les valeurs de propriété, le chargement différé et le chargement explicite sont également appelés chargement différé.

En général, si vous savez que vous avez besoin de données associées pour chaque entité récupérée, le chargement rapide offre les meilleures performances, car une requête unique envoyée à la base de données est généralement plus efficace que les requêtes distinctes pour chaque entité récupérée. Par exemple, dans les exemples ci-dessus, supposons que chaque service dispose de dix cours connexes. L’exemple de chargement pressé entraînerait une seule requête (jointure) et un seul aller-retour vers la base de données. Les exemples de chargement paresseux et de chargement explicite entraînent onze requêtes et onze allers-retours vers la base de données. Les allers-retours supplémentaires à la base de données sont particulièrement nuisibles pour les performances lorsque la latence est élevée.

D’autre part, dans certains scénarios, le chargement paresseux est plus efficace. Un chargement rapide peut entraîner la génération d’une jointure très complexe, que SQL Server ne pouvez pas traiter efficacement. Ou si vous avez besoin d’accéder aux propriétés de navigation d’une entité uniquement pour un sous-ensemble d’entités que vous traitez, le chargement différé peut être plus efficace, car le chargement pressé récupérerait plus de données que nécessaire. Si les performances sont essentielles, il est préférable de tester les performances des deux façons afin d’effectuer le meilleur choix.

En règle générale, vous n’utilisez le chargement explicite que lorsque vous avez désactivé le chargement paresseux. L’un des scénarios où vous devez désactiver le chargement paresseux est pendant la sérialisation. Le chargement paresseux et la sérialisation ne se mélangent pas bien, et si vous n’êtes pas prudent, vous pouvez interroger beaucoup plus de données que prévu lorsque le chargement paresseux est activé. La sérialisation fonctionne généralement en accédant à chaque propriété sur un instance d’un type. L’accès aux propriétés déclenche le chargement différé, et ces entités chargées lazy sont sérialisées. Le processus de sérialisation accède ensuite à chaque propriété des entités chargées paresseux, ce qui peut entraîner un chargement et une sérialisation encore plus paresseux. Pour empêcher cette réaction en chaîne d’écoulement, désactivez le chargement paresseux avant de sérialiser une entité.

La classe de contexte de base de données effectue un chargement différé par défaut. Il existe deux façons de désactiver le chargement paresseux :

  • Pour des propriétés de navigation spécifiques, omettez le virtual mot clé lorsque vous déclarez la propriété.

  • Pour toutes les propriétés de navigation, définissez sur LazyLoadingEnabledfalse. Par exemple, vous pouvez placer le code suivant dans le constructeur de votre classe de contexte :

    this.Configuration.LazyLoadingEnabled = false;
    

Le chargement paresseux peut masquer le code qui provoque des problèmes de performances. Par exemple, le code qui ne spécifie pas de chargement pressé ou explicite, mais qui traite un volume élevé d’entités et qui utilise plusieurs propriétés de navigation à chaque itération peut être très inefficace (en raison de nombreux allers-retours vers la base de données). Une application qui fonctionne bien dans le développement à l’aide d’un serveur SQL server local peut rencontrer des problèmes de performances lorsqu’elle est déplacée vers Azure SQL Database en raison de la latence et du chargement paresseux accrus. Le profilage des requêtes de base de données avec une charge de test réaliste vous aidera à déterminer si le chargement différé est approprié. Pour plus d’informations, consultez Démystification des stratégies Entity Framework : chargement de données associées et Utilisation d’Entity Framework pour réduire la latence réseau à SQL Azure.

Créer une page d’index de cours qui affiche le nom du service

L’entité Course inclut une propriété de navigation qui contient l’entité Department du service auquel le cours est affecté. Pour afficher le nom du service affecté dans une liste de cours, vous devez obtenir la Name propriété à partir de l’entité Department qui se trouve dans la Course.Department propriété de navigation.

Créez un contrôleur nommé CourseController pour le type d’entité, à l’aide Course des mêmes options que celles que vous avez effectuées précédemment pour le Student contrôleur, comme illustré dans l’illustration suivante (sauf contrairement à l’image, votre classe de contexte se trouve dans l’espace de noms DAL, et non dans l’espace de noms Models) :

Add_Controller_dialog_box_for_Course_controller

Ouvrez Controllers\CourseController.cs et examinez la Index méthode :

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

La génération de modèles automatique a spécifié un chargement hâtif pour la propriété de navigation Department à l’aide de la méthode Include.

Ouvrez Views\Course\Index.cshtml et remplacez le code existant par le code suivant. Les modifications apparaissent en surbrillance :

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

Vous avez apporté les modifications suivantes au code généré automatiquement :

  • Changement de l’en-tête : Index a été remplacé par Courses.
  • Déplacez les liens de ligne vers la gauche.
  • Ajout d’une colonne sous l’en-tête Numéro qui affiche la valeur de la CourseID propriété. (Par défaut, les clés primaires ne sont pas générées, car elles sont normalement sans signification pour les utilisateurs finaux. Toutefois, dans ce cas, la clé primaire est significative et vous souhaitez l’afficher.)
  • Modification du dernier en-tête de colonne de DepartmentID (nom de la clé étrangère de l’entité Department ) en Department.

Notez que pour la dernière colonne, le code généré affiche la Name propriété de l’entité Department chargée dans la Department propriété de navigation :

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

Exécutez la page (sélectionnez l’onglet Cours dans la page d’accueil de Contoso University) pour afficher la liste avec les noms de service.

Courses_index_page_with_department_names

Créer une page d’index des instructeurs qui affiche les cours et les inscriptions

Dans cette section, vous allez créer un contrôleur et une vue pour l’entité Instructor afin d’afficher la page Index des instructeurs :

Capture d’écran montrant la page Index des instructeurs avec un instructeur et l’un de ses cours sélectionnés.

Cette page lit et affiche les données associées comme suit :

  • La liste des formateurs affiche les données associées de l’entité OfficeAssignment. Il existe une relation un-à-zéro-ou-un entre les entités Instructor et OfficeAssignment. Vous allez utiliser un chargement hâtif pour les entités OfficeAssignment. Comme expliqué précédemment, le chargement hâtif est généralement plus efficace lorsque vous avez besoin des données associées pour toutes les lignes extraites de la table primaire. Dans ce cas, vous souhaitez afficher les affectations de bureaux pour tous les formateurs affichés.
  • Quand l’utilisateur sélectionne un formateur, les entités Course associées sont affichées. Il existe une relation plusieurs-à-plusieurs entre les entités Instructor et Course. Vous utilisez le chargement hâtif pour les entités Course et leurs entités Department associées. Dans ce cas, le chargement paresseux peut être plus efficace, car vous avez besoin de cours uniquement pour l’instructeur sélectionné. Toutefois, cet exemple montre comment utiliser le chargement hâtif pour des propriétés de navigation dans des entités qui se trouvent elles-mêmes dans des propriétés de navigation.
  • Quand l’utilisateur sélectionne un cours, les données associées du jeu d’entités Enrollments s’affichent. Il existe une relation un-à-plusieurs entre les entités Course et Enrollment. Vous allez ajouter un chargement explicite pour les Enrollment entités et leurs entités associées Student . (Le chargement explicite n’est pas nécessaire, car le chargement paresseux est activé, mais cela montre comment effectuer un chargement explicite.)

Créer un modèle d’affichage pour l’affichage d’index instructeur

La page Index de l’instructeur affiche trois tables différentes. Par conséquent, vous allez créer un modèle de vue qui comprend trois propriétés, chacune contenant les données d’une des tables.

Dans le dossier ViewModels , créez InstructorIndexData.cs et remplacez le code existant par le code suivant :

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

Ajout d’un style pour les lignes sélectionnées

Pour marquer les lignes sélectionnées, vous avez besoin d’une couleur d’arrière-plan différente. Pour fournir un style pour cette interface utilisateur, ajoutez le code en surbrillance suivant à la section /* info and errors */Content\Site.css, comme indiqué ci-dessous :

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

Création du contrôleur et des vues de l’instructeur

Créez un InstructorController contrôleur comme illustré dans l’illustration suivante :

Add_Controller_dialog_box_for_Instructor_controller

Ouvrez Controllers\InstructorController.cs et ajoutez une using instruction pour l’espace de ViewModels noms :

using ContosoUniversity.ViewModels;

Le code généré automatiquement dans la méthode spécifie un Index chargement hâtif uniquement pour la propriété de OfficeAssignment navigation :

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

Remplacez la Index méthode par le code suivant pour charger des données connexes supplémentaires et les placer dans le modèle d’affichage :

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

La méthode accepte les données de routage facultatives (id) et un paramètre de chaîne de requête (courseID) qui fournissent les valeurs d’ID de l’instructeur sélectionné et du cours sélectionné, et transmet toutes les données requises à la vue. Ces paramètres sont fournis par les liens hypertexte Select dans la page.

Conseil

Données de routage

Les données de routage sont des données que le classeur de modèles a trouvées dans un segment d’URL spécifié dans la table de routage. Par exemple, l’itinéraire par défaut spécifie les segments controller, actionet id :

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

Dans l’URL suivante, l’itinéraire par défaut est mappé Instructor en tant que controller, Index en tant que action et 1 en tant que id; il s’agit de valeurs de données de routage.

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

« ?courseID=2021 » est une valeur de chaîne de requête. Le classeur de modèles fonctionne également si vous passez le id en tant que valeur de chaîne de requête :

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

Les URL sont créées par ActionLink des instructions dans la vue Razor. Dans le code suivant, le id paramètre correspond à l’itinéraire par défaut. Il est donc id ajouté aux données de routage.

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

Dans le code suivant, courseID ne correspond pas à un paramètre dans l’itinéraire par défaut, il est donc ajouté en tant que chaîne de requête.

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

Le code commence par créer une instance du modèle de vue et la placer dans la liste des formateurs. Le code spécifie un chargement hâtif pour la Instructor.OfficeAssignment propriété de navigation et Instructor.Courses .

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

La deuxième Include méthode charge Courses, et pour chaque cours chargé, elle effectue un chargement avec ardeur pour la Course.Department propriété de navigation.

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

Comme mentionné précédemment, le chargement hâtif n’est pas nécessaire, mais est effectué pour améliorer les performances. Étant donné que la vue nécessite toujours l’entité OfficeAssignment, il est plus efficace de l’extraire dans la même requête. Course les entités sont requises lorsqu’un instructeur est sélectionné dans la page web. Il est donc préférable de charger avec ardeur plutôt que de ne charger paresseux que si la page est affichée plus souvent avec un cours sélectionné que sans.

Si un ID d’instructeur a été sélectionné, l’instructeur sélectionné est récupéré à partir de la liste des instructeurs dans le modèle d’affichage. La propriété Courses du modèle d’affichage est ensuite chargée avec les entités Course de la propriété de navigation Courses de ce formateur.

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

La Where méthode retourne une collection, mais dans ce cas, les critères passés à cette méthode entraînent le retour d’une seule Instructor entité. La méthode Single convertit la collection en une seule entité Instructor, ce qui vous permet d’accéder à la propriété Courses de cette entité.

Vous utilisez la méthode Single sur une collection quand vous savez que la collection n’aura qu’un seul élément. La Single méthode lève une exception si la collection qui lui a été transmise est vide ou s’il y a plusieurs éléments. Une alternative est SingleOrDefault, qui retourne une valeur par défaut (null dans ce cas) si la collection est vide. Toutefois, dans ce cas, cela entraînerait toujours une exception (en essayant de trouver une Courses propriété sur une null référence) et le message d’exception indiquerait moins clairement la cause du problème. Lorsque vous appelez la Single méthode, vous pouvez également passer la Where condition au lieu d’appeler la Where méthode séparément :

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

À la place de :

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

Ensuite, si un cours a été sélectionné, le cours sélectionné est récupéré à partir de la liste des cours dans le modèle de vue. Ensuite, la propriété du modèle de Enrollments vue est chargée avec les entités de la Enrollment propriété de navigation de Enrollments ce cours.

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

Modification de la vue d’index de l’instructeur

Dans Views\Instructor\Index.cshtml, remplacez le code existant par le code suivant. Les modifications apparaissent en surbrillance :

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

Vous avez apporté les modifications suivantes au code existant :

  • Vous avez changé la classe de modèle en InstructorIndexData.

  • Vous avez changé le titre de la page en remplaçant Index par Instructors.

  • Déplacement des colonnes de liaison de ligne vers la gauche.

  • Suppression de la colonne FullName .

  • Ajout d’une colonne Office qui s’affiche item.OfficeAssignment.Location uniquement si item.OfficeAssignment n’est pas null. (Comme il s’agit d’une relation un-à-zéro ou un, il peut ne pas y avoir d’entité associée OfficeAssignment .)

    <td> 
        @if (item.OfficeAssignment != null) 
        { 
            @item.OfficeAssignment.Location  
        } 
    </td>
    
  • Ajout de code qui ajoute class="selectedrow" dynamiquement à l’élément tr de l’instructeur sélectionné. Cela définit une couleur d’arrière-plan pour la ligne sélectionnée à l’aide de la classe CSS que vous avez créée précédemment. (L’attribut valign sera utile dans le tutoriel suivant lorsque vous ajoutez une colonne à plusieurs lignes à la table.)

    string selectedRow = ""; 
    if (item.InstructorID == ViewBag.InstructorID) 
    { 
        selectedRow = "selectedrow"; 
    } 
    <tr class="@selectedRow" valign="top">
    
  • Ajout d’un nouveau ActionLink intitulé Select juste avant les autres liens dans chaque ligne, ce qui entraîne l’envoi de l’ID d’instructeur sélectionné à la Index méthode.

Exécutez l’application et sélectionnez l’onglet Instructeurs . La page affiche la Location propriété des entités associées OfficeAssignment et une cellule de tableau vide lorsqu’il n’y a pas d’entité associée OfficeAssignment .

Instructors_index_page_with_nothing_selected

Dans le fichier Views\Instructor\Index.cshtml , après l’élément fermant table (à la fin du fichier), ajoutez le code en surbrillance suivant. Cela affiche la liste des cours liés à un instructeur lorsqu’un instructeur est sélectionné.

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

Ce code lit la propriété Courses du modèle de vue pour afficher la liste des cours. Il fournit également un Select lien hypertexte qui envoie l’ID du cours sélectionné à la méthode d’action Index .

Notes

Le fichier .css est mis en cache par les navigateurs. Si vous ne voyez pas les modifications lorsque vous exécutez l’application, effectuez une actualisation matérielle (maintenez la touche Ctrl enfoncée tout en cliquant sur le bouton Actualiser , ou appuyez sur Ctrl+F5).

Exécutez la page et sélectionnez un instructeur. Vous voyez à présent une grille qui affiche les cours affectés au formateur sélectionné et, pour chaque cours, vous voyez le nom du département affecté.

Instructors_index_page_with_instructor_selected

Après le bloc de code que vous venez d’ajouter, ajoutez le code suivant. Ceci affiche la liste des étudiants qui sont inscrits à un cours quand ce cours est sélectionné.

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

Ce code lit la propriété Enrollments du modèle de vue pour afficher la liste des étudiants inscrits dans ce cours.

Exécutez la page et sélectionnez un instructeur. Ensuite, sélectionnez un cours pour afficher la liste des étudiants inscrits et leurs notes.

Capture d’écran de la page Index des instructeurs avec un instructeur et l’un de ses cours sélectionnés.

Ajout d’un chargement explicite

Ouvrez InstructorController.cs et examinez comment la Index méthode obtient la liste des inscriptions pour un cours sélectionné :

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

Lorsque vous avez récupéré la liste des instructeurs, vous avez spécifié un chargement hâtif pour la Courses propriété de navigation et pour la Department propriété de chaque cours. Ensuite, vous placez la Courses collection dans le modèle d’affichage, et vous accédez maintenant à la Enrollments propriété de navigation à partir d’une entité de cette collection. Étant donné que vous n’avez pas spécifié de chargement hâtif pour la Course.Enrollments propriété de navigation, les données de cette propriété apparaissent dans la page à la suite d’un chargement différé.

Si vous avez désactivé le chargement différé sans modifier le code d’une autre manière, la Enrollments propriété est null, quel que soit le nombre d’inscriptions du cours. Dans ce cas, pour charger la Enrollments propriété, vous devez spécifier un chargement hâtif ou un chargement explicite. Vous avez déjà vu comment effectuer un chargement hâtif. Pour voir un exemple de chargement explicite, remplacez la Index méthode par le code suivant, qui charge explicitement la Enrollments propriété. Le code modifié est mis en surbrillance.

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

Après avoir obtenu l’entité sélectionnée Course , le nouveau code charge explicitement la propriété de navigation de Enrollments ce cours :

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

Ensuite, il charge explicitement l’entité associée Student de chaque Enrollment entité :

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

Notez que vous utilisez la Collection méthode pour charger une propriété de collection, mais pour une propriété qui ne contient qu’une seule entité, vous utilisez la Reference méthode . Vous pouvez exécuter la page Index de l’instructeur maintenant et vous ne verrez aucune différence dans ce qui est affiché sur la page, bien que vous ayez modifié la façon dont les données sont récupérées.

Résumé

Vous avez maintenant utilisé les trois méthodes (paresseux, impatient et explicite) pour charger des données associées dans les propriétés de navigation. Dans le didacticiel suivant, vous apprendrez à mettre à jour les données associées.

Vous trouverez des liens vers d’autres ressources Entity Framework dans le ASP.NET Data Access Content Map.