Erste Schritte mit Entity Framework 4.0 Database First und ASP.NET 4 Web Forms – Teil 4
von Tom Dykstra
Die Beispielwebanwendung der Contoso University veranschaulicht das Erstellen ASP.NET Web Forms Anwendungen mit Entity Framework 4.0 und Visual Studio 2010. Informationen zur Tutorialreihe finden Sie im ersten Tutorial der Reihe.
Arbeiten mit verwandten Daten
Im vorherigen Tutorial haben Sie das EntityDataSource
Steuerelement zum Filtern, Sortieren und Gruppieren von Daten verwendet. In diesem Tutorial zeigen Sie verwandte Daten an und aktualisieren sie.
Sie erstellen die Seite "Dozenten" mit einer Liste von Kursleitern. Wenn Sie einen Kursleiter auswählen, wird eine Liste der Kurse angezeigt, die von diesem Kursleiter unterrichtet werden. Wenn Sie einen Kurs auswählen, werden Details für den Kurs und eine Liste der Kursteilnehmer angezeigt, die für den Kurs registriert sind. Sie können den Kursleiternamen, das Einstellungsdatum und die Bürozuweisung bearbeiten. Die Office-Zuweisung ist ein separater Entitätssatz, auf den Sie über eine Navigationseigenschaft zugreifen.
Sie können master Daten verknüpfen, um Daten im Markup oder im Code zu detailieren. In diesem Teil des Tutorials verwenden Sie beide Methoden.
Anzeigen und Aktualisieren verwandter Entitäten in einem GridView-Steuerelement
Erstellen Sie eine neue Webseite namens Instructors.aspx, die die Seite Site.Master master verwendet, und fügen Sie dem Steuerelement das folgende Markup mit dem Content
Namen Content2
hinzu:
<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>
Dieses Markup erstellt ein EntityDataSource
Steuerelement, das Kursleiter auswählt und Updates aktiviert. Das div
-Element konfiguriert das Markup für das Rendern auf der linken Seite, sodass Sie später rechts eine Spalte hinzufügen können.
Fügen Sie zwischen dem EntityDataSource
Markup und dem schließenden </div>
Tag das folgende Markup hinzu, das ein GridView
Steuerelement und ein Label
Steuerelement erstellt, das Sie für Fehlermeldungen verwenden:
<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>
Dieses GridView
Steuerelement aktiviert die Zeilenauswahl, hebt die ausgewählte Zeile mit einer hellgrauen Hintergrundfarbe hervor und gibt Handler (die Sie später erstellen) für die SelectedIndexChanged
Ereignisse und Updating
an. Außerdem wird für die DataKeyNames
-Eigenschaft angegebenPersonID
, sodass der Schlüsselwert der ausgewählten Zeile an ein anderes Steuerelement übergeben werden kann, das Sie später hinzufügen werden.
Die letzte Spalte enthält die Office-Zuweisung des Kursleiters, die in einer Navigationseigenschaft der Person
Entität gespeichert wird, da sie von einer zugeordneten Entität stammt. Beachten Sie, dass das EditItemTemplate
-Element anstelle von Bind
angibtEval
, da das GridView
Steuerelement nicht direkt an Navigationseigenschaften gebunden werden kann, um sie zu aktualisieren. Sie aktualisieren die Office-Zuweisung im Code. Dazu benötigen Sie einen Verweis auf das TextBox
Steuerelement, und Sie erhalten und speichern es im TextBox
-Ereignis des Steuerelements Init
.
GridView
Das -Steuerelement folgt einem Label
Steuerelement, das für Fehlermeldungen verwendet wird. Die -Eigenschaft des Steuerelements ist false
, und der Ansichtszustand Visible
ist deaktiviert, sodass die Bezeichnung nur angezeigt wird, wenn code sie als Reaktion auf einen Fehler sichtbar macht.
Öffnen Sie die Datei Instructors.aspx.cs, und fügen Sie die folgende using
Anweisung hinzu:
using ContosoUniversity.DAL;
Fügen Sie unmittelbar nach der Deklaration des teilweisen Klassennamens ein privates Klassenfeld hinzu, um einen Verweis auf das Textfeld für die Office-Zuweisung zu enthalten.
private TextBox instructorOfficeTextBox;
Fügen Sie einen Stub für den SelectedIndexChanged
Ereignishandler hinzu, den Sie später code hinzufügen. Fügen Sie auch einen Handler für das Ereignis des Office-Zuweisungssteuerelements TextBox
Init
hinzu, damit Sie einen Verweis auf das TextBox
Steuerelement speichern können. Sie verwenden diesen Verweis, um den vom Benutzer eingegebenen Wert abzurufen, um die Entität zu aktualisieren, die der Navigationseigenschaft zugeordnet ist.
protected void InstructorsGridView_SelectedIndexChanged(object sender, EventArgs e)
{
}
protected void InstructorOfficeTextBox_Init(object sender, EventArgs e)
{
instructorOfficeTextBox = sender as TextBox;
}
Sie verwenden das GridView
-Ereignis des Steuerelements Updating
, um die Location
Eigenschaft der zugeordneten OfficeAssignment
Entität zu aktualisieren. Fügen Sie den folgenden Handler für das Updating
Ereignis hinzu:
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.
}
}
}
Dieser Code wird ausgeführt, wenn der Benutzer in einer GridView
Zeile auf Aktualisieren klickt. Der Code verwendet LINQ to Entities, um die Entität abzurufen, die OfficeAssignment
der aktuellen Person
Entität zugeordnet ist, wobei die PersonID
der ausgewählten Zeile aus dem Ereignisargument verwendet wird.
Der Code führt dann je nach Wert im InstructorOfficeTextBox
Steuerelement eine der folgenden Aktionen aus:
- Wenn das Textfeld über einen Wert verfügt und keine
OfficeAssignment
Zu aktualisierende Entität vorhanden ist, wird eine entität erstellt. - Wenn das Textfeld über einen Wert verfügt und eine
OfficeAssignment
Entität vorhanden ist, wird derLocation
Eigenschaftswert aktualisiert. - Wenn das Textfeld leer ist und eine
OfficeAssignment
Entität vorhanden ist, wird die Entität gelöscht.
Danach werden die Änderungen an der Datenbank gespeichert. Wenn eine Ausnahme auftritt, wird eine Fehlermeldung angezeigt.
Führen Sie die Seite aus.
Klicken Sie auf Bearbeiten , und alle Felder werden in Textfelder geändert.
Ändern Sie einen dieser Werte, einschließlich der Office-Zuweisung. Klicken Sie auf Aktualisieren , und Die Änderungen werden in der Liste widerspiegelt.
Anzeigen verwandter Entitäten in einem separaten Steuerelement
Jeder Kursleiter kann einen oder mehrere Kurse unterrichten. Daher fügen Sie ein EntityDataSource
Steuerelement und ein GridView
Steuerelement hinzu, um die Kurse aufzulisten, die dem jeweiligen Kursleiter zugeordnet sind, der im Kursleiter-Steuerelement GridView
ausgewählt ist. Um eine Überschrift und das EntityDataSource
Steuerelement für Kursentitäten zu erstellen, fügen Sie das folgende Markup zwischen dem Fehlermeldungssteuerelement Label
und dem schließenden </div>
Tag hinzu:
<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>
Der Where
Parameter enthält den Wert des PersonID
Kursleiters, dessen Zeile im InstructorsGridView
Steuerelement ausgewählt ist. Die Where
-Eigenschaft enthält einen Subselect-Befehl, der alle zugeordneten Person
Entitäten aus der Navigationseigenschaft People
einer Course
Entität abruft und die Course
Entität nur dann auswählt, wenn eine der zugeordneten Person
Entitäten den ausgewählten PersonID
Wert enthält.
Um das GridView
Steuerelement zu erstellen, fügen Sie das folgende Markup unmittelbar nach dem CoursesEntityDataSource
Steuerelement (vor dem schließenden </div>
Tag) hinzu:
<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>
Da keine Kurse angezeigt werden, wenn kein Kursleiter ausgewählt ist, ist ein EmptyDataTemplate
Element enthalten.
Führen Sie die Seite aus.
Wählen Sie einen Kursleiter aus, dem mindestens ein Kurs zugewiesen ist, und die Kurse werden in der Liste angezeigt. (Hinweis: Obwohl das Datenbankschema mehrere Kurse zulässt, enthält kein Kursleiter in den mit der Datenbank bereitgestellten Testdaten mehr als einen Kurs. Sie können kurse selbst zur Datenbank hinzufügen, indem Sie das Fenster Server Explorer oder die Seite CoursesAdd.aspx verwenden, die Sie in einem späteren Tutorial hinzufügen werden.)
Das CoursesGridView
Steuerelement zeigt nur einige Kursfelder an. Um alle Details für einen Kurs anzuzeigen, verwenden Sie ein DetailsView
Steuerelement für den kurs, den der Benutzer auswählt. Fügen Sie in Instructors.aspx das folgende Markup nach dem schließenden </div>
Tag hinzu (stellen Sie sicher, dass Sie dieses Markup nach dem schließenden div-Tag platzieren, nicht davor):
<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>
Dieses Markup erstellt ein EntityDataSource
Steuerelement, das an den Courses
Entitätssatz gebunden ist. Die Where
-Eigenschaft wählt einen Kurs mithilfe des CourseID
Werts der ausgewählten Zeile im Kurssteuerelement GridView
aus. Das Markup gibt einen Handler für das Ereignis an, den Selected
Sie später zum Anzeigen von Schülernoten verwenden, was eine weitere Ebene niedriger in der Hierarchie ist.
Erstellen Sie in Instructors.aspx.cs den folgenden Stub für die CourseDetailsEntityDataSource_Selected
-Methode. (Sie füllen diesen Stub später im Tutorial aus. Vorerst benötigen Sie ihn, damit die Seite kompiliert und ausgeführt wird.)
protected void CourseDetailsEntityDataSource_Selected(object sender, EntityDataSourceSelectedEventArgs e)
{
}
Führen Sie die Seite aus.
Zunächst gibt es keine Kursdetails, da kein Kurs ausgewählt ist. Wählen Sie einen Kursleiter aus, dem ein Kurs zugewiesen ist, und wählen Sie dann einen Kurs aus, um die Details anzuzeigen.
Verwenden des EntityDataSource-Ereignisses "Selected" zum Anzeigen verwandter Daten
Schließlich möchten Sie alle eingeschriebenen Kursteilnehmer und ihre Noten für den ausgewählten Kurs anzeigen. Dazu verwenden Sie das Selected
-Ereignis des Steuerelements, das EntityDataSource
an den Kurs DetailsView
gebunden ist.
Fügen Sie in Instructors.aspx das folgende Markup nach dem DetailsView
Steuerelement hinzu:
<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>
Dieses Markup erstellt ein ListView
Steuerelement, das eine Liste der Kursteilnehmer und deren Noten für den ausgewählten Kurs anzeigt. Es wird keine Datenquelle angegeben, da Sie das Steuerelement im Code datenbinden. Das EmptyDataTemplate
-Element stellt eine Meldung bereit, die angezeigt werden soll, wenn kein Kurs ausgewählt ist. In diesem Fall müssen keine Kursteilnehmer angezeigt werden. Das LayoutTemplate
-Element erstellt eine HTML-Tabelle zum Anzeigen der Liste und ItemTemplate
gibt die anzuzeigenden Spalten an. Die Schüler-ID und die Schülernote stammen aus der StudentGrade
Entität, und der Kursteilnehmername stammt von der Person
Entität, die das Entity Framework in der Person
Navigationseigenschaft der StudentGrade
Entität zur Verfügung stellt.
Ersetzen Sie in Instructors.aspx.cs die stubbed-out-Methode CourseDetailsEntityDataSource_Selected
durch den folgenden Code:
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();
}
}
Das Ereignisargument für dieses Ereignis stellt die ausgewählten Daten in Form einer Auflistung bereit, die null Elemente enthält, wenn nichts ausgewählt ist, oder ein Element, wenn eine Course
Entität ausgewählt ist. Wenn eine Course
Entität ausgewählt ist, verwendet der Code die First
-Methode, um die Auflistung in ein einzelnes Objekt zu konvertieren. Anschließend werden Entitäten aus der Navigationseigenschaft abgerufen StudentGrade
, in eine Auflistung konvertiert und das Steuerelement an die GradesListView
Auflistung gebunden.
Dies ist ausreichend, um Noten anzuzeigen, aber Sie möchten sicherstellen, dass die Nachricht in der leeren Datenvorlage angezeigt wird, wenn die Seite zum ersten Mal angezeigt wird und wenn ein Kurs nicht ausgewählt ist. Erstellen Sie dazu die folgende Methode, die Sie an zwei Stellen aufrufen:
private void ClearStudentGradesDataSource()
{
var emptyStudentGradesList = new List<StudentGrade>();
GradesListView.DataSource = emptyStudentGradesList;
GradesListView.DataBind();
}
Rufen Sie diese neue Methode über die Page_Load
-Methode auf, um die leere Datenvorlage beim ersten Anzeigen der Seite anzuzeigen. Und rufen Sie es aus der InstructorsGridView_SelectedIndexChanged
-Methode auf, da dieses Ereignis ausgelöst wird, wenn ein Kursleiter ausgewählt wird. Dies bedeutet, dass neue Kurse in das Kurssteuerelement GridView
geladen werden und noch keiner ausgewählt ist. Hier sind die beiden Aufrufe:
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
ClearStudentGradesDataSource();
}
}
protected void InstructorsGridView_SelectedIndexChanged(object sender, EventArgs e)
{
ClearStudentGradesDataSource();
}
Führen Sie die Seite aus.
Wählen Sie einen Kursleiter aus, dem ein Kurs zugewiesen ist, und wählen Sie dann den Kurs aus.
Sie haben nun einige Möglichkeiten zum Arbeiten mit verwandten Daten kennengelernt. Im folgenden Tutorial erfahren Sie, wie Sie Beziehungen zwischen vorhandenen Entitäten hinzufügen, Beziehungen entfernen und eine neue Entität hinzufügen, die eine Beziehung zu einer vorhandenen Entität aufweist.