Prise en main avec Entity Framework 4.0 Database First et ASP.NET 4 Web Forms - Partie 2
par Tom Dykstra
L’exemple d’application web Contoso University montre comment créer des applications ASP.NET Web Forms à l’aide d’Entity Framework 4.0 et de Visual Studio 2010. Pour plus d’informations sur la série de didacticiels, consultez le premier didacticiel de la série
Contrôle EntityDataSource
Dans le tutoriel précédent, vous avez créé un site web, une base de données et un modèle de données. Dans ce tutoriel, vous utilisez le EntityDataSource
contrôle fourni par ASP.NET afin de faciliter l’utilisation d’un modèle de données Entity Framework. Vous allez créer un GridView
contrôle pour afficher et modifier les données des étudiants, un DetailsView
contrôle pour ajouter de nouveaux étudiants et un DropDownList
contrôle pour sélectionner un service (que vous utiliserez ultérieurement pour afficher les cours associés).
Notez que dans cette application, vous n’ajouterez pas de validation d’entrée aux pages qui mettent à jour la base de données, et que certaines des opérations de gestion des erreurs ne seront pas aussi robustes que ce qui serait nécessaire dans une application de production. Cela permet au didacticiel de se concentrer sur Entity Framework et d’empêcher qu’il ne soit trop long. Pour plus d’informations sur l’ajout de ces fonctionnalités à votre application, consultez Validation de l’entrée utilisateur dans pages Web ASP.NET et Gestion des erreurs dans ASP.NET pages et applications.
Ajout et configuration du contrôle EntityDataSource
Vous allez commencer par configurer un EntityDataSource
contrôle pour lire Person
les entités du jeu d’entités People
.
Vérifiez que Visual Studio est ouvert et que vous travaillez avec le projet que vous avez créé dans la partie 1. Si vous n’avez pas généré le projet depuis que vous avez créé le modèle de données ou depuis la dernière modification que vous y avez apportée, générez le projet maintenant. Les modifications apportées au modèle de données ne sont pas mises à la disposition du concepteur tant que le projet n’est pas généré.
Créez une page web à l’aide du formulaire web à l’aide du modèle Page maître et nommez-la Students.aspx.
Spécifiez Site.Master comme page master. Toutes les pages que vous créez pour ces tutoriels utilisent cette page master.
En mode Source , ajoutez un h2
titre au Content
contrôle nommé Content2
, comme illustré dans l’exemple suivant :
<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">
<h2>Student List</h2>
</asp:Content>
Sous l’onglet Données de la boîte à outils, faites glisser un EntityDataSource
contrôle vers la page, déposez-le sous le titre et remplacez l’ID par StudentsEntityDataSource
:
<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">
<h2>Student List</h2>
<asp:EntityDataSource ID="StudentsEntityDataSource" runat="server">
</asp:EntityDataSource>
</asp:Content>
Basculez vers le mode Création , cliquez sur la balise active du contrôle de source de données, puis cliquez sur Configurer la source de données pour lancer l’Assistant Configuration de la source de données .
À l’étape de l’Assistant Configurer ObjectContext , sélectionnez SchoolEntities comme valeur pour Named Connection, puis schoolEntities comme valeur DefaultContainerName . Cliquez ensuite sur Suivant.
Remarque : si vous obtenez la boîte de dialogue suivante à ce stade, vous devez générer le projet avant de continuer.
À l’étape Configurer la sélection des données, sélectionnez Personnes comme valeur pour EntitySetName. Sous Sélectionner, vérifiez que la zone Sélectionner un case activée est cochée. Sélectionnez ensuite les options permettant d’activer la mise à jour et la suppression. Lorsque vous avez terminé, cliquez sur Terminer.
Configuration des règles de base de données pour autoriser la suppression
Vous allez créer une page qui permet aux utilisateurs de supprimer des étudiants de la Person
table, qui a trois relations avec d’autres tables (Course
, StudentGrade
et OfficeAssignment
). Par défaut, la base de données vous empêche de supprimer une ligne dans Person
s’il existe des lignes associées dans l’une des autres tables. Vous pouvez d’abord supprimer manuellement les lignes associées, ou configurer la base de données pour les supprimer automatiquement lorsque vous supprimez une Person
ligne. Pour les enregistrements d’étudiants dans ce tutoriel, vous allez configurer la base de données pour supprimer automatiquement les données associées. Étant donné que les étudiants peuvent avoir des lignes associées uniquement dans la StudentGrade
table, vous devez configurer une seule des trois relations.
Si vous utilisez le fichier School.mdf que vous avez téléchargé à partir du projet qui accompagne ce didacticiel, vous pouvez ignorer cette section, car ces modifications de configuration ont déjà été effectuées. Si vous avez créé la base de données en exécutant un script, configurez la base de données en effectuant les procédures suivantes.
Dans Server Explorer, ouvrez le diagramme de base de données que vous avez créé dans la partie 1. Cliquez avec le bouton droit sur la relation entre Person
et StudentGrade
(la ligne entre les tables), puis sélectionnez Propriétés.
Dans la fenêtre Propriétés , développez INSERT et UPDATE Specification et définissez la propriété DeleteRule sur Cascade.
Enregistrez et fermez le diagramme. Si vous êtes invité à mettre à jour la base de données, cliquez sur Oui.
Pour vous assurer que le modèle maintient les entités en mémoire synchronisées avec ce que fait la base de données, vous devez définir des règles correspondantes dans le modèle de données. Ouvrez SchoolModel.edmx, cliquez avec le bouton droit sur la ligne d’association entre Person
et StudentGrade
, puis sélectionnez Propriétés.
Dans la fenêtre Propriétés , définissez End1 OnDelete surCascade.
Enregistrez et fermez le fichier SchoolModel.edmx , puis régénérez le projet.
En général, lorsque la base de données change, vous avez plusieurs choix pour synchroniser le modèle :
- Pour certains types de modifications (par exemple, l’ajout ou l’actualisation de tables, de vues ou de procédures stockées), cliquez avec le bouton droit dans le concepteur et sélectionnez Mettre à jour le modèle à partir de la base de données pour que le concepteur apporte les modifications automatiquement.
- Régénérez le modèle de données.
- Effectuez des mises à jour manuelles comme celle-ci.
Dans ce cas, vous auriez peut-être régénéré le modèle ou actualisé les tables affectées par le changement de relation, mais vous devrez ensuite modifier à nouveau le nom du champ (de FirstName
à FirstMidName
).
Utilisation d’un contrôle GridView pour lire et mettre à jour des entités
Dans cette section, vous allez utiliser un GridView
contrôle pour afficher, mettre à jour ou supprimer des étudiants.
Ouvrez ou basculez vers Students.aspx et basculez en mode Création . Sous l’onglet Données de la boîte à outils, faites glisser un GridView
contrôle à droite du contrôle, nommez-le EntityDataSource
StudentsGridView
, cliquez sur la balise active, puis sélectionnez StudentsEntityDataSource comme source de données.
Cliquez sur Actualiser le schéma (cliquez sur Oui si vous êtes invité à confirmer), puis sur Activer la pagination, Activer le tri, Activer la modification et Activer la suppression.
Cliquez sur Modifier les colonnes.
Dans la zone Champs sélectionnés , supprimez PersonID, LastName et HireDate. En règle générale, vous n’affichez pas de clé d’enregistrement pour les utilisateurs, la date d’embauche n’est pas pertinente pour les étudiants, et vous devez placer les deux parties du nom dans un seul champ. Vous n’avez donc besoin que d’un des champs de nom.)
Sélectionnez le champ FirstMidName , puis cliquez sur Convertir ce champ en templateField.
Faites de même pour EnrollmentDate.
Cliquez sur OK , puis basculez en mode Source . Les autres modifications seront plus faciles à effectuer directement dans le balisage. Le GridView
balisage de contrôle ressemble maintenant à l’exemple suivant.
<asp:GridView ID="StudentsGridView" runat="server" AllowPaging="True"
AllowSorting="True" AutoGenerateColumns="False" DataKeyNames="PersonID"
DataSourceID="StudentsEntityDataSource">
<Columns>
<asp:CommandField ShowDeleteButton="True" ShowEditButton="True" />
<asp:TemplateField HeaderText="FirstMidName" SortExpression="FirstMidName">
<EditItemTemplate>
<asp:TextBox ID="TextBox1" runat="server" Text='<%# Bind("FirstMidName") %>'></asp:TextBox>
</EditItemTemplate>
<ItemTemplate>
<asp:Label ID="Label1" runat="server" Text='<%# Bind("FirstMidName") %>'></asp:Label>
</ItemTemplate>
</asp:TemplateField>
<asp:TemplateField HeaderText="EnrollmentDate" SortExpression="EnrollmentDate">
<EditItemTemplate>
<asp:TextBox ID="TextBox2" runat="server" Text='<%# Bind("EnrollmentDate") %>'></asp:TextBox>
</EditItemTemplate>
<ItemTemplate>
<asp:Label ID="Label2" runat="server" Text='<%# Bind("EnrollmentDate") %>'></asp:Label>
</ItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>
La première colonne après le champ de commande est un champ de modèle qui affiche actuellement le prénom. Modifiez le balisage de ce champ de modèle pour qu’il ressemble à l’exemple suivant :
<asp:TemplateField HeaderText="Name" SortExpression="LastName">
<EditItemTemplate>
<asp:TextBox ID="LastNameTextBox" runat="server" Text='<%# Bind("LastName") %>'></asp:TextBox>
<asp:TextBox ID="FirstNameTextBox" runat="server" Text='<%# Bind("FirstMidName") %>'></asp:TextBox>
</EditItemTemplate>
<ItemTemplate>
<asp:Label ID="LastNameLabel" runat="server" Text='<%# Eval("LastName") %>'></asp:Label>,
<asp:Label ID="FirstNameLabel" runat="server" Text='<%# Eval("FirstMidName") %>'></asp:Label>
</ItemTemplate>
</asp:TemplateField>
En mode d’affichage, deux Label
contrôles affichent le prénom et le nom. En mode édition, deux zones de texte sont fournies pour vous permettre de modifier le prénom et le nom. Comme avec les Label
contrôles en mode d’affichage, vous utilisez Bind
des expressions et Eval
exactement comme vous le feriez avec ASP.NET contrôles de source de données qui se connectent directement aux bases de données. La seule différence est que vous spécifiez des propriétés d’entité au lieu de colonnes de base de données.
La dernière colonne est un champ de modèle qui affiche la date d’inscription. Modifiez le balisage de ce champ pour qu’il ressemble à l’exemple suivant :
<asp:TemplateField HeaderText="Enrollment Date" SortExpression="EnrollmentDate">
<EditItemTemplate>
<asp:TextBox ID="EnrollmentDateTextBox" runat="server" Text='<%# Bind("EnrollmentDate", "{0:d}") %>'></asp:TextBox>
</EditItemTemplate>
<ItemTemplate>
<asp:Label ID="EnrollmentDateLabel" runat="server" Text='<%# Eval("EnrollmentDate", "{0:d}") %>'></asp:Label>
</ItemTemplate>
</asp:TemplateField>
En mode d’affichage et d’édition, la chaîne de format « {0,d} » entraîne l’affichage de la date au format « date courte ». (Votre ordinateur peut être configuré pour afficher ce format différemment des images d’écran présentées dans ce didacticiel.)
Notez que dans chacun de ces champs de modèle, le concepteur a utilisé une Bind
expression par défaut, mais que vous l’avez remplacée par une Eval
expression dans les ItemTemplate
éléments. L’expression Bind
rend les données disponibles dans GridView
les propriétés de contrôle au cas où vous deviez accéder aux données dans le code. Dans cette page, vous n’avez pas besoin d’accéder à ces données dans le code. Vous pouvez donc utiliser Eval
, ce qui est plus efficace. Pour plus d’informations, consultez Obtention de vos données hors des contrôles de données.
Révision du balisage du contrôle EntityDataSource pour améliorer les performances
Dans le balisage du EntityDataSource
contrôle, supprimez les ConnectionString
attributs et DefaultContainerName
et remplacez-les par un ContextTypeName="ContosoUniversity.DAL.SchoolEntities"
attribut. Il s’agit d’une modification que vous devez apporter chaque fois que vous créez un EntityDataSource
contrôle, sauf si vous devez utiliser une connexion différente de celle codée en dur dans la classe de contexte d’objet. L’utilisation de l’attribut ContextTypeName
offre les avantages suivants :
- Performances améliorées. Lorsque le
EntityDataSource
contrôle initialise le modèle de données à l’aideConnectionString
des attributs etDefaultContainerName
, il effectue un travail supplémentaire pour charger les métadonnées sur chaque requête. Cela n’est pas nécessaire si vous spécifiez l’attributContextTypeName
. - Le chargement paresseux est activé par défaut dans les classes de contexte d’objet générées (comme
SchoolEntities
dans ce tutoriel) dans Entity Framework 4.0. Cela signifie que les propriétés de navigation sont automatiquement chargées avec les données associées dès que vous en avez besoin. Le chargement paresseux est expliqué plus en détail plus loin dans ce tutoriel. - Toutes les personnalisations que vous avez appliquées à la classe de contexte d’objet (dans ce cas, la
SchoolEntities
classe) seront disponibles pour les contrôles qui utilisent leEntityDataSource
contrôle. La personnalisation de la classe de contexte d’objet est une rubrique avancée qui n’est pas abordée dans cette série de tutoriels. Pour plus d’informations, consultez Extension des types générés par Entity Framework.
Le balisage ressemblera maintenant à l’exemple suivant (l’ordre des propriétés peut être différent) :
<asp:EntityDataSource ID="StudentsEntityDataSource" runat="server"
ContextTypeName="ContosoUniversity.DAL.SchoolEntities" EnableFlattening="False"
EntitySetName="People"
EnableDelete="True" EnableUpdate="True">
</asp:EntityDataSource>
L’attribut EnableFlattening
fait référence à une fonctionnalité qui était nécessaire dans les versions antérieures d’Entity Framework, car les colonnes de clé étrangère n’étaient pas exposées en tant que propriétés d’entité. La version actuelle permet d’utiliser des associations de clés étrangères, ce qui signifie que les propriétés de clé étrangère sont exposées pour toutes les associations, sauf plusieurs-à-plusieurs. Si vos entités ont des propriétés de clé étrangère et aucun type complexe, vous pouvez laisser cet attribut défini sur False
. Ne supprimez pas l’attribut du balisage, car la valeur par défaut est True
. Pour plus d’informations, consultez Aplatissement d’objets (EntityDataSource).
Exécutez la page et vous voyez une liste d’étudiants et d’employés (vous allez filtrer uniquement les étudiants dans le tutoriel suivant). Le prénom et le nom sont affichés ensemble.
Pour trier l’affichage, cliquez sur le nom d’une colonne.
Cliquez sur Modifier dans n’importe quelle ligne. Des zones de texte s’affichent dans lesquelles vous pouvez modifier le prénom et le nom.
Le bouton Supprimer fonctionne également. Cliquez sur Supprimer pour une ligne qui a une date d’inscription et la ligne disparaît. (Les lignes sans date d’inscription représentent des instructeurs et vous pouvez obtenir une erreur d’intégrité référentielle. Dans le tutoriel suivant, vous allez filtrer cette liste pour inclure uniquement les étudiants.)
Affichage des données à partir d’une propriété de navigation
Supposons maintenant que vous voulez savoir combien de cours chaque étudiant est inscrit. Entity Framework fournit ces informations dans la StudentGrades
propriété de navigation de l’entité Person
. Étant donné que la conception de la base de données ne permet pas à un étudiant d’être inscrit à un cours sans qu’une note soit affectée, pour ce tutoriel, vous pouvez supposer que le fait d’avoir une ligne dans la StudentGrade
ligne de table associée à un cours est identique à l’inscription au cours. (La Courses
propriété de navigation est réservée aux instructeurs.)
Lorsque vous utilisez l’attribut ContextTypeName
du EntityDataSource
contrôle, Entity Framework récupère automatiquement les informations d’une propriété de navigation lorsque vous accédez à cette propriété. C’est ce qu’on appelle le chargement paresseux. Toutefois, cela peut s’avérer inefficace, car cela entraîne un appel distinct à la base de données chaque fois que des informations supplémentaires sont nécessaires. Si vous avez besoin de données de la propriété de navigation pour chaque entité retournée par le EntityDataSource
contrôle, il est plus efficace de récupérer les données associées avec l’entité elle-même dans un seul appel à la base de données. C’est ce qu’on appelle le chargement avide, et vous spécifiez un chargement pressant pour une propriété de navigation en définissant la Include
propriété du EntityDataSource
contrôle.
Dans Students.aspx, vous souhaitez afficher le nombre de cours pour chaque étudiant. Le chargement pressé est donc le meilleur choix. Si vous affichiez tous les étudiants, mais que vous affichiez le nombre de cours uniquement pour quelques-uns d’entre eux (ce qui nécessiterait d’écrire du code en plus du balisage), le chargement paresseux peut être un meilleur choix.
Ouvrez ou basculez vers Students.aspx, basculez en mode Création , sélectionnez StudentsEntityDataSource
, puis, dans la fenêtre Propriétés , définissez la propriété Include sur StudentGrades. (Si vous souhaitez obtenir plusieurs propriétés de navigation, vous pouvez spécifier leurs noms séparés par des virgules , par exemple , StudentGrades, Courses.)
Basculez vers la vue Source . Dans le StudentsGridView
contrôle, après le dernier asp:TemplateField
élément, ajoutez le nouveau champ de modèle suivant :
<asp:TemplateField HeaderText="Number of Courses">
<ItemTemplate>
<asp:Label ID="Label1" runat="server" Text='<%# Eval("StudentGrades.Count") %>'></asp:Label>
</ItemTemplate>
</asp:TemplateField>
Dans l’expression Eval
, vous pouvez référencer la propriété StudentGrades
de navigation . Étant donné que cette propriété contient une collection, elle a une Count
propriété que vous pouvez utiliser pour afficher le nombre de cours auxquels l’étudiant est inscrit. Dans un tutoriel ultérieur, vous verrez comment afficher les données des propriétés de navigation qui contiennent des entités uniques au lieu de collections. (Notez que vous ne pouvez pas utiliser d’éléments BoundField
pour afficher les données des propriétés de navigation.)
Exécutez la page et vous voyez maintenant combien de cours chaque étudiant est inscrit.
Utilisation d’un contrôle DetailsView pour insérer des entités
L’étape suivante consiste à créer une page avec un DetailsView
contrôle qui vous permettra d’ajouter de nouveaux étudiants. Fermez le navigateur, puis créez une page web à l’aide de la page Site.Master master. Nommez la page StudentsAdd.aspx, puis basculez vers la vue Source .
Ajoutez le balisage suivant pour remplacer le balisage existant pour le Content
contrôle nommé Content2
:
<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">
<h2>Add New Students</h2>
<asp:EntityDataSource ID="StudentsEntityDataSource" runat="server"
ContextTypeName="ContosoUniversity.DAL.SchoolEntities" EnableFlattening="False"
EnableInsert="True" EntitySetName="People">
</asp:EntityDataSource>
<asp:DetailsView ID="StudentsDetailsView" runat="server"
DataSourceID="StudentsEntityDataSource" AutoGenerateRows="False"
DefaultMode="Insert">
<Fields>
<asp:BoundField DataField="FirstMidName" HeaderText="First Name"
SortExpression="FirstMidName" />
<asp:BoundField DataField="LastName" HeaderText="Last Name"
SortExpression="LastName" />
<asp:BoundField DataField="EnrollmentDate" HeaderText="Enrollment Date"
SortExpression="EnrollmentDate" />
<asp:CommandField ShowInsertButton="True" />
</Fields>
</asp:DetailsView>
</asp:Content>
Ce balisage crée un EntityDataSource
contrôle similaire à celui que vous avez créé dans Students.aspx, sauf qu’il permet l’insertion. Comme avec le GridView
contrôle, les champs liés du contrôle sont codés exactement comme ils le DetailsView
seraient pour un contrôle de données qui se connecte directement à une base de données, sauf qu’ils référencent les propriétés d’entité. Dans ce cas, le DetailsView
contrôle étant utilisé uniquement pour insérer des lignes, vous avez défini le mode par défaut sur Insert
.
Exécutez la page et ajoutez un nouvel étudiant.
Rien ne se produit après l’insertion d’un nouvel étudiant, mais si vous exécutez maintenant Students.aspx, vous verrez les nouvelles informations sur l’étudiant.
Affichage de données dans une liste de Drop-Down
Dans les étapes suivantes, vous allez lier un contrôle à un DropDownList
jeu d’entités à l’aide d’un EntityDataSource
contrôle. Dans cette partie du tutoriel, vous ne ferez pas grand-chose avec cette liste. Dans les parties suivantes, toutefois, vous utiliserez la liste pour permettre aux utilisateurs de sélectionner un service pour afficher les cours associés au service.
Créez une page web nommée Courses.aspx. En mode Source , ajoutez un titre au Content
contrôle nommé Content2
:
<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">
<h2>Courses by Department</h2>
</asp:Content>
En mode Création , ajoutez un EntityDataSource
contrôle à la page comme vous l’avez fait auparavant, sauf que cette fois, nommez-le DepartmentsEntityDataSource
. Sélectionnez Départements comme valeur EntitySetName , puis sélectionnez uniquement les propriétés DepartmentID et Name .
Sous l’onglet Standard de la boîte à outils, faites glisser un DropDownList
contrôle vers la page, nommez-le DepartmentsDropDownList
, cliquez sur la balise active, puis sélectionnez Choisir une source de données pour démarrer l’Assistant Configuration dataSource.
À l’étape Choisir une source de données , sélectionnez DepartmentEntityDataSource comme source de données, cliquez sur Actualiser le schéma, puis sélectionnez Nom comme champ de données à afficher et DepartmentID comme champ de données de valeur. Cliquez sur OK.
La méthode que vous utilisez pour lier le contrôle à l’aide d’Entity Framework est la même qu’avec d’autres contrôles de source de données ASP.NET, sauf si vous spécifiez des entités et des propriétés d’entité.
Basculez vers la vue Source et ajoutez « Sélectionner un service : » immédiatement avant le DropDownList
contrôle.
Select a department:
<asp:DropDownList ID="DropDownList1" runat="server"
DataSourceID="EntityDataSource1" DataTextField="Name"
DataValueField="DepartmentID">
</asp:DropDownList>
Pour rappel, modifiez le balisage du EntityDataSource
contrôle à ce stade en remplaçant les ConnectionString
attributs et DefaultContainerName
par un ContextTypeName="ContosoUniversity.DAL.SchoolEntities"
attribut. Il est souvent préférable d’attendre que vous ayez créé le contrôle lié aux données lié au contrôle de source de données avant de modifier le balisage du EntityDataSource
contrôle, car après avoir effectué la modification, le concepteur ne vous fournira pas d’option Actualiser le schéma dans le contrôle lié aux données.
Exécutez la page et vous pouvez sélectionner un service dans la liste déroulante.
Cette opération termine l’introduction à l’utilisation du EntityDataSource
contrôle. L’utilisation de ce contrôle n’est généralement pas différente de l’utilisation d’autres contrôles de source de données ASP.NET, sauf que vous référencez des entités et des propriétés au lieu de tables et de colonnes. La seule exception est lorsque vous souhaitez accéder aux propriétés de navigation. Dans le tutoriel suivant, vous verrez que la syntaxe que vous utilisez avec EntityDataSource
le contrôle peut également différer des autres contrôles de source de données lorsque vous filtrez, regroupez et triez des données.