Prise en main avec Entity Framework 4.0 Database First et ASP.NET 4 Web Forms - Partie 4
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
Utilisation des données associées
Dans le tutoriel précédent, vous avez utilisé le EntityDataSource
contrôle pour filtrer, trier et regrouper des données. Dans ce tutoriel, vous allez afficher et mettre à jour les données associées.
Vous allez créer la page Instructeurs qui affiche une liste d’instructeurs. Lorsque vous sélectionnez un instructeur, vous voyez une liste des cours enseignés par cet instructeur. Lorsque vous sélectionnez un cours, vous voyez les détails du cours et une liste des étudiants inscrits au cours. Vous pouvez modifier le nom de l’instructeur, la date d’embauche et l’affectation du bureau. L’affectation office est un jeu d’entités distinct auquel vous accédez via une propriété de navigation.
Vous pouvez lier master données pour détailler les données dans le balisage ou dans le code. Dans cette partie du tutoriel, vous allez utiliser les deux méthodes.
Affichage et mise à jour d’entités associées dans un contrôle GridView
Créez une page web nommée Instructors.aspx qui utilise la page master Site.Master et ajoutez le balisage suivant au Content
contrôle nommé Content2
:
<h2>Instructors</h2>
<div>
<asp:EntityDataSource ID="InstructorsEntityDataSource" runat="server"
ContextTypeName="ContosoUniversity.DAL.SchoolEntities" EnableFlattening="False"
EntitySetName="People"
Where="it.HireDate is not null" Include="OfficeAssignment" EnableUpdate="True">
</asp:EntityDataSource>
</div>
Ce balisage crée un EntityDataSource
contrôle qui sélectionne les instructeurs et active les mises à jour. L’élément div
configure le balisage pour qu’il s’affiche à gauche afin que vous puissiez ajouter une colonne à droite ultérieurement.
Entre le EntityDataSource
balisage et la balise de fermeture </div>
, ajoutez le balisage suivant qui crée un GridView
contrôle et un Label
contrôle que vous utiliserez pour les messages d’erreur :
<asp:GridView ID="InstructorsGridView" runat="server" AllowPaging="True" AllowSorting="True"
AutoGenerateColumns="False" DataKeyNames="PersonID" DataSourceID="InstructorsEntityDataSource"
OnSelectedIndexChanged="InstructorsGridView_SelectedIndexChanged"
SelectedRowStyle-BackColor="LightGray"
onrowupdating="InstructorsGridView_RowUpdating">
<Columns>
<asp:CommandField ShowSelectButton="True" ShowEditButton="True" />
<asp:TemplateField HeaderText="Name" SortExpression="LastName">
<ItemTemplate>
<asp:Label ID="InstructorLastNameLabel" runat="server" Text='<%# Eval("LastName") %>'></asp:Label>,
<asp:Label ID="InstructorFirstNameLabel" runat="server" Text='<%# Eval("FirstMidName") %>'></asp:Label>
</ItemTemplate>
<EditItemTemplate>
<asp:TextBox ID="InstructorLastNameTextBox" runat="server" Text='<%# Bind("FirstMidName") %>' Width="7em"></asp:TextBox>
<asp:TextBox ID="InstructorFirstNameTextBox" runat="server" Text='<%# Bind("LastName") %>' Width="7em"></asp:TextBox>
</EditItemTemplate>
</asp:TemplateField>
<asp:TemplateField HeaderText="Hire Date" SortExpression="HireDate">
<ItemTemplate>
<asp:Label ID="InstructorHireDateLabel" runat="server" Text='<%# Eval("HireDate", "{0:d}") %>'></asp:Label>
</ItemTemplate>
<EditItemTemplate>
<asp:TextBox ID="InstructorHireDateTextBox" runat="server" Text='<%# Bind("HireDate", "{0:d}") %>' Width="7em"></asp:TextBox>
</EditItemTemplate>
</asp:TemplateField>
<asp:TemplateField HeaderText="Office Assignment" SortExpression="OfficeAssignment.Location">
<ItemTemplate>
<asp:Label ID="InstructorOfficeLabel" runat="server" Text='<%# Eval("OfficeAssignment.Location") %>'></asp:Label>
</ItemTemplate>
<EditItemTemplate>
<asp:TextBox ID="InstructorOfficeTextBox" runat="server"
Text='<%# Eval("OfficeAssignment.Location") %>' Width="7em"
oninit="InstructorOfficeTextBox_Init"></asp:TextBox>
</EditItemTemplate>
</asp:TemplateField>
</Columns>
<SelectedRowStyle BackColor="LightGray"></SelectedRowStyle>
</asp:GridView>
<asp:Label ID="ErrorMessageLabel" runat="server" Text="" Visible="false" ViewStateMode="Disabled"></asp:Label>
Ce GridView
contrôle active la sélection de ligne, met en surbrillance la ligne sélectionnée avec une couleur d’arrière-plan gris clair et spécifie des gestionnaires (que vous créerez ultérieurement) pour les SelectedIndexChanged
événements et Updating
. Il spécifie PersonID
également pour la DataKeyNames
propriété , afin que la valeur de clé de la ligne sélectionnée puisse être passée à un autre contrôle que vous ajouterez ultérieurement.
La dernière colonne contient l’affectation du bureau de l’instructeur, qui est stockée dans une propriété de navigation de l’entité Person
, car elle provient d’une entité associée. Notez que l’élément EditItemTemplate
spécifie Eval
au lieu de Bind
, car le GridView
contrôle ne peut pas lier directement aux propriétés de navigation pour les mettre à jour. Vous allez mettre à jour l’affectation office dans le code. Pour ce faire, vous aurez besoin d’une référence au TextBox
contrôle, et vous l’obtiendrez et l’enregistrerez dans l’événement TextBox
du Init
contrôle.
Suivant le GridView
contrôle se trouve un Label
contrôle qui est utilisé pour les messages d’erreur. La propriété du Visible
contrôle est false
, et l’état d’affichage est désactivé, de sorte que l’étiquette s’affiche uniquement lorsque le code la rend visible en réponse à une erreur.
Ouvrez le fichier Instructors.aspx.cs et ajoutez l’instruction suivante using
:
using ContosoUniversity.DAL;
Ajoutez un champ de classe privée immédiatement après la déclaration de nom de classe partielle pour contenir une référence à la zone de texte d’affectation de bureau.
private TextBox instructorOfficeTextBox;
Ajoutez un stub pour le SelectedIndexChanged
gestionnaire d’événements que vous allez ajouter du code pour plus tard. Ajoutez également un gestionnaire pour l’événement du contrôle d’affectation TextBox
de Init
bureau afin de pouvoir stocker une référence au TextBox
contrôle. Vous allez utiliser cette référence pour obtenir la valeur entrée par l’utilisateur afin de mettre à jour l’entité associée à la propriété de navigation.
protected void InstructorsGridView_SelectedIndexChanged(object sender, EventArgs e)
{
}
protected void InstructorOfficeTextBox_Init(object sender, EventArgs e)
{
instructorOfficeTextBox = sender as TextBox;
}
Vous allez utiliser l’événement GridView
du Updating
contrôle pour mettre à jour la Location
propriété de l’entité associée OfficeAssignment
. Ajoutez le gestionnaire suivant pour l’événement Updating
:
protected void InstructorsGridView_RowUpdating(object sender, GridViewUpdateEventArgs e)
{
using (var context = new SchoolEntities())
{
var instructorBeingUpdated = Convert.ToInt32(e.Keys[0]);
var officeAssignment = (from o in context.OfficeAssignments
where o.InstructorID == instructorBeingUpdated
select o).FirstOrDefault();
try
{
if (String.IsNullOrWhiteSpace(instructorOfficeTextBox.Text) == false)
{
if (officeAssignment == null)
{
context.OfficeAssignments.AddObject(OfficeAssignment.CreateOfficeAssignment(instructorBeingUpdated, instructorOfficeTextBox.Text, null));
}
else
{
officeAssignment.Location = instructorOfficeTextBox.Text;
}
}
else
{
if (officeAssignment != null)
{
context.DeleteObject(officeAssignment);
}
}
context.SaveChanges();
}
catch (Exception)
{
e.Cancel = true;
ErrorMessageLabel.Visible = true;
ErrorMessageLabel.Text = "Update failed.";
//Add code to log the error.
}
}
}
Ce code est exécuté lorsque l’utilisateur clique sur Mettre à jour dans une GridView
ligne. Le code utilise LINQ to Entities pour récupérer l’entité OfficeAssignment
associée à l’entité actuellePerson
, en utilisant le PersonID
de la ligne sélectionnée à partir de l’argument d’événement.
Le code effectue ensuite l’une des actions suivantes en fonction de la valeur dans le InstructorOfficeTextBox
contrôle :
- Si la zone de texte a une valeur et qu’aucune entité n’est
OfficeAssignment
à mettre à jour, elle en crée une. - Si la zone de texte a une valeur et qu’il existe une
OfficeAssignment
entité, elle met à jour la valeur de laLocation
propriété. - Si la zone de texte est vide et qu’une
OfficeAssignment
entité existe, l’entité est supprimée.
Après cela, il enregistre les modifications apportées à la base de données. Si une exception se produit, un message d’erreur s’affiche.
Exécutez la page.
Cliquez sur Modifier et tous les champs passent aux zones de texte.
Modifiez l’une de ces valeurs, y compris l’affectation office. Cliquez sur Mettre à jour pour voir les modifications répercutées dans la liste.
Affichage d’entités associées dans un contrôle distinct
Chaque instructeur peut enseigner un ou plusieurs cours. Vous allez donc ajouter un EntityDataSource
contrôle et un GridView
contrôle pour répertorier les cours associés à l’instructeur sélectionné dans le contrôle instructeurs GridView
. Pour créer un en-tête et le contrôle pour les EntityDataSource
entités de cours, ajoutez le balisage suivant entre le contrôle de message Label
d’erreur et la balise de fermeture </div>
:
<h3>Courses Taught</h3>
<asp:EntityDataSource ID="CoursesEntityDataSource" runat="server"
ContextTypeName="ContosoUniversity.DAL.SchoolEntities" EnableFlattening="False"
EntitySetName="Courses"
Where="@PersonID IN (SELECT VALUE instructor.PersonID FROM it.People AS instructor)">
<WhereParameters>
<asp:ControlParameter ControlID="InstructorsGridView" Type="Int32" Name="PersonID" PropertyName="SelectedValue" />
</WhereParameters>
</asp:EntityDataSource>
Le Where
paramètre contient la valeur de l’instructeur PersonID
dont la ligne est sélectionnée dans le InstructorsGridView
contrôle . La Where
propriété contient une commande de sous-sélection qui obtient toutes les entités associées Person
à partir de la propriété de navigation d’une Course
People
entité et ne sélectionne l’entité Course
que si l’une des entités associées Person
contient la valeur sélectionnée PersonID
.
Pour créer le GridView
contrôle, ajoutez le balisage suivant immédiatement après le CoursesEntityDataSource
contrôle (avant la balise de fermeture </div>
) :
<asp:GridView ID="CoursesGridView" runat="server"
DataSourceID="CoursesEntityDataSource"
AllowSorting="True" AutoGenerateColumns="False"
SelectedRowStyle-BackColor="LightGray"
DataKeyNames="CourseID">
<EmptyDataTemplate>
<p>No courses found.</p>
</EmptyDataTemplate>
<Columns>
<asp:CommandField ShowSelectButton="True" />
<asp:BoundField DataField="CourseID" HeaderText="ID" ReadOnly="True" SortExpression="CourseID" />
<asp:BoundField DataField="Title" HeaderText="Title" SortExpression="Title" />
<asp:TemplateField HeaderText="Department" SortExpression="DepartmentID">
<ItemTemplate>
<asp:Label ID="GridViewDepartmentLabel" runat="server" Text='<%# Eval("Department.Name") %>'></asp:Label>
</ItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>
Étant donné qu’aucun cours ne s’affiche si aucun instructeur n’est sélectionné, un EmptyDataTemplate
élément est inclus.
Exécutez la page.
Sélectionnez un instructeur auquel un ou plusieurs cours sont attribués, et le ou les cours apparaissent dans la liste. (Remarque : bien que le schéma de base de données autorise plusieurs cours, dans les données de test fournies avec la base de données, aucun instructeur n’a réellement plus d’un cours. Vous pouvez ajouter vous-même des cours à la base de données à l’aide de la fenêtre Server Explorer ou de la page CoursesAdd.aspx, que vous ajouterez dans un didacticiel ultérieur.)
Le CoursesGridView
contrôle affiche seulement quelques champs de cours. Pour afficher tous les détails d’un cours, vous allez utiliser un DetailsView
contrôle pour le cours que l’utilisateur sélectionne. Dans Instructors.aspx, ajoutez le balisage suivant après la balise fermante </div>
(veillez à placer ce balisage après la balise div fermante, et non avant celle-ci) :
<div>
<h3>Course Details</h3>
<asp:EntityDataSource ID="CourseDetailsEntityDataSource" runat="server"
ContextTypeName="ContosoUniversity.DAL.SchoolEntities" EnableFlattening="False"
EntitySetName="Courses"
AutoGenerateWhereClause="False" Where="it.CourseID = @CourseID" Include="Department,OnlineCourse,OnsiteCourse,StudentGrades.Person"
OnSelected="CourseDetailsEntityDataSource_Selected">
<WhereParameters>
<asp:ControlParameter ControlID="CoursesGridView" Type="Int32" Name="CourseID" PropertyName="SelectedValue" />
</WhereParameters>
</asp:EntityDataSource>
<asp:DetailsView ID="CourseDetailsView" runat="server" AutoGenerateRows="False"
DataSourceID="CourseDetailsEntityDataSource">
<EmptyDataTemplate>
<p>
No course selected.</p>
</EmptyDataTemplate>
<Fields>
<asp:BoundField DataField="CourseID" HeaderText="ID" ReadOnly="True" SortExpression="CourseID" />
<asp:BoundField DataField="Title" HeaderText="Title" SortExpression="Title" />
<asp:BoundField DataField="Credits" HeaderText="Credits" SortExpression="Credits" />
<asp:TemplateField HeaderText="Department">
<ItemTemplate>
<asp:Label ID="DetailsViewDepartmentLabel" runat="server" Text='<%# Eval("Department.Name") %>'></asp:Label>
</ItemTemplate>
</asp:TemplateField>
<asp:TemplateField HeaderText="Location">
<ItemTemplate>
<asp:Label ID="LocationLabel" runat="server" Text='<%# Eval("OnsiteCourse.Location") %>'></asp:Label>
</ItemTemplate>
</asp:TemplateField>
<asp:TemplateField HeaderText="URL">
<ItemTemplate>
<asp:Label ID="URLLabel" runat="server" Text='<%# Eval("OnlineCourse.URL") %>'></asp:Label>
</ItemTemplate>
</asp:TemplateField>
</Fields>
</asp:DetailsView>
</div>
Ce balisage crée un EntityDataSource
contrôle lié au jeu d’entités Courses
. La Where
propriété sélectionne un cours à l’aide de la CourseID
valeur de la ligne sélectionnée dans le contrôle courses GridView
. Le balisage spécifie un gestionnaire pour l’événement Selected
, que vous utiliserez ultérieurement pour afficher les notes des étudiants, qui est un autre niveau inférieur dans la hiérarchie.
Dans Instructors.aspx.cs, créez le stub suivant pour la CourseDetailsEntityDataSource_Selected
méthode . (Vous remplirez ce stub plus loin dans le tutoriel ; pour l’instant, vous en avez besoin pour que la page soit compilée et exécutée.)
protected void CourseDetailsEntityDataSource_Selected(object sender, EntityDataSourceSelectedEventArgs e)
{
}
Exécutez la page.
Au départ, il n’y a pas de détails sur le cours, car aucun cours n’est sélectionné. Sélectionnez un instructeur auquel un cours est attribué, puis sélectionnez un cours pour afficher les détails.
Utilisation de l’événement EntityDataSource « Selected » pour afficher les données associées
Enfin, vous souhaitez afficher tous les étudiants inscrits et leurs notes pour le cours sélectionné. Pour ce faire, vous allez utiliser l’événement Selected
du EntityDataSource
contrôle lié au cours DetailsView
.
Dans Instructors.aspx, ajoutez le balisage suivant après le DetailsView
contrôle :
<h3>Student Grades</h3>
<asp:ListView ID="GradesListView" runat="server">
<EmptyDataTemplate>
<p>No student grades found.</p>
</EmptyDataTemplate>
<LayoutTemplate>
<table border="1" runat="server" id="itemPlaceholderContainer">
<tr runat="server">
<th runat="server">
Name
</th>
<th runat="server">
Grade
</th>
</tr>
<tr id="itemPlaceholder" runat="server">
</tr>
</table>
</LayoutTemplate>
<ItemTemplate>
<tr>
<td>
<asp:Label ID="StudentLastNameLabel" runat="server" Text='<%# Eval("Person.LastName") %>' />,
<asp:Label ID="StudentFirstNameLabel" runat="server" Text='<%# Eval("Person.FirstMidName") %>' />
</td>
<td>
<asp:Label ID="StudentGradeLabel" runat="server" Text='<%# Eval("Grade") %>' />
</td>
</tr>
</ItemTemplate>
</asp:ListView>
Ce balisage crée un ListView
contrôle qui affiche une liste des étudiants et leurs notes pour le cours sélectionné. Aucune source de données n’est spécifiée, car vous allez lier le contrôle dans le code. L’élément EmptyDataTemplate
fournit un message à afficher lorsqu’aucun cours n’est sélectionné. Dans ce cas, aucun étudiant n’est à afficher. L’élément LayoutTemplate
crée un tableau HTML pour afficher la liste, et spécifie ItemTemplate
les colonnes à afficher. L’ID d’étudiant et la note de l’étudiant proviennent de l’entité StudentGrade
, et le nom de l’étudiant provient de l’entité Person
que Entity Framework rend disponible dans la Person
propriété de navigation de l’entité StudentGrade
.
Dans Instructors.aspx.cs, remplacez la méthode stubbed-out CourseDetailsEntityDataSource_Selected
par le code suivant :
protected void CourseDetailsEntityDataSource_Selected(object sender, EntityDataSourceSelectedEventArgs e)
{
var course = e.Results.Cast<Course>().FirstOrDefault();
if (course != null)
{
var studentGrades = course.StudentGrades.ToList();
GradesListView.DataSource = studentGrades;
GradesListView.DataBind();
}
}
L’argument événement de cet événement fournit les données sélectionnées sous la forme d’une collection, qui aura zéro élément si rien n’est sélectionné ou un élément si une Course
entité est sélectionnée. Si une Course
entité est sélectionnée, le code utilise la First
méthode pour convertir la collection en un seul objet. Il obtient StudentGrade
ensuite les entités de la propriété de navigation, les convertit en collection et lie le GradesListView
contrôle à la collection.
Cela est suffisant pour afficher les notes, mais vous souhaitez vous assurer que le message dans le modèle de données vide s’affiche la première fois que la page est affichée et chaque fois qu’un cours n’est pas sélectionné. Pour ce faire, créez la méthode suivante, que vous allez appeler à partir de deux emplacements :
private void ClearStudentGradesDataSource()
{
var emptyStudentGradesList = new List<StudentGrade>();
GradesListView.DataSource = emptyStudentGradesList;
GradesListView.DataBind();
}
Appelez cette nouvelle méthode à partir de la Page_Load
méthode pour afficher le modèle de données vide la première fois que la page est affichée. Et appelez-le à partir de la InstructorsGridView_SelectedIndexChanged
méthode, car cet événement est déclenché lorsqu’un instructeur est sélectionné, ce qui signifie que les nouveaux cours sont chargés dans le contrôle cours GridView
et qu’aucun n’est encore sélectionné. Voici les deux appels :
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
ClearStudentGradesDataSource();
}
}
protected void InstructorsGridView_SelectedIndexChanged(object sender, EventArgs e)
{
ClearStudentGradesDataSource();
}
Exécutez la page.
Sélectionnez un instructeur auquel un cours est attribué, puis sélectionnez le cours.
Vous avez maintenant vu plusieurs façons d’utiliser des données associées. Dans le tutoriel suivant, vous allez apprendre à ajouter des relations entre des entités existantes, à supprimer des relations et à ajouter une nouvelle entité qui a une relation à une entité existante.