Freigeben über


Erste Schritte mit Entity Framework 4.0-Datenbank und ASP.NET 4 Webformularen – Teil 4

Von Tom Dykstra

Die Contoso University-Beispielwebanwendung veranschaulicht, wie ASP.NET Web Forms-Anwendungen mithilfe von Entity Framework 4.0 und Visual Studio 2010 erstellt werden. Informationen zur Lernprogrammreihe finden Sie im ersten Lernprogramm in der Reihe

Im vorherigen Lernprogramm haben Sie das EntityDataSource Steuerelement zum Filtern, Sortieren und Gruppieren von Daten verwendet. In diesem Lernprogramm zeigen Sie verwandte Daten an und aktualisieren sie.

Sie erstellen die Seite "Kursleiter", auf der eine Liste der Kursleiter angezeigt wird. 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 im Kurs registrierten Kursteilnehmer angezeigt. Sie können den Namen des Kursleiters, 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 Masterdaten mit Detaildaten im Markup oder im Code verknüpfen. In diesem Teil des Lernprogramms verwenden Sie beide Methoden.

Bild01

Erstellen Sie eine neue Webseite mit dem Namen Instructors.aspx , die die Gestaltungsvorlage "Site.Master " verwendet, und fügen Sie dem Content Steuerelement das folgende Markup hinzu 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>

Dieses Markup erstellt ein EntityDataSource Steuerelement, das Kursleiter auswählt und Updates aktiviert. Das div Element konfiguriert Markup so, dass es links gerendert wird, sodass Sie später eine Spalte rechts 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 und Updating die Ereignisse an. Außerdem wird für die PersonID-Eigenschaft DataKeyNames angegeben, 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 Bürozuweisung 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 Eval anstelle von Bind angibt, weil das GridView-Steuerelement nicht direkt an Navigationseigenschaften binden kann, um sie zu aktualisieren. Sie aktualisieren die Bürozuordnung im Code. Dazu benötigen Sie einen Verweis auf das TextBox Steuerelement, und Sie erhalten und speichern dies im Ereignis des TextBox Steuerelements Init .

Nach dem GridView Steuerelement handelt es sich um ein Label Steuerelement, das für Fehlermeldungen verwendet wird. Die Eigenschaft Visible des Steuerelements ist false, und der Viewstate ist deaktiviert, sodass die Bezeichnung nur angezeigt wird, wenn der Code sie als Reaktion auf einen Fehler sichtbar macht.

Öffnen Sie die Instructors.aspx.cs Datei, und fügen Sie die folgende using Anweisung hinzu:

using ContosoUniversity.DAL;

Fügen Sie unmittelbar nach der Deklaration des Teilklassennamens ein privates Klassenfeld hinzu, um einen Verweis auf das Office-Zuordnungs-Textfeld zu halten.

private TextBox instructorOfficeTextBox;

Fügen Sie einen Stub für den SelectedIndexChanged Ereignishandler hinzu, dem Sie später Code hinzufügen werden. Fügen Sie außerdem einen Handler für das Ereignis des Office-Zuweisungssteuerelements TextBoxInit hinzu, damit Sie einen Verweis auf das TextBox Steuerelement speichern können. Sie verwenden diesen Verweis, um den Wert abzurufen, den der Benutzer eingegeben hat, 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 Zeile auf GridView klickt. Der Code verwendet LINQ to Entities, um die OfficeAssignment Entität abzurufen, die der aktuellen Person Entität zugeordnet ist, mithilfe PersonID der ausgewählten Zeile aus dem Ereignisargument.

Der Code führt dann eine der folgenden Aktionen abhängig vom Wert im InstructorOfficeTextBox Steuerelement aus:

  • Wenn das Textfeld einen Wert aufweist und keine OfficeAssignment-Entität zur Aktualisierung vorhanden ist, wird eine erstellt.
  • Wenn das Textfeld einen Wert aufweist und eine OfficeAssignment Entität vorhanden ist, wird der Location Eigenschaftswert aktualisiert.
  • Wenn das Textfeld leer ist und eine OfficeAssignment Entität vorhanden ist, wird die Entität gelöscht.

Danach werden die Änderungen in der Datenbank gespeichert. Wenn eine Ausnahme auftritt, wird eine Fehlermeldung angezeigt.

Laden Sie die Seite.

Bild02

Klicken Sie auf "Bearbeiten" , und alle Felder werden in Textfelder geändert.

Bild03

Ändern Sie einen dieser Werte, einschließlich Office-Zuweisung. Klicken Sie auf "Aktualisieren ", und die Änderungen werden in der Liste angezeigt.

Jeder Kursleiter kann einen oder mehrere Kurse unterrichten, sodass Sie ein EntityDataSource Steuerelement und ein GridView Steuerelement hinzufügen, um die Kurse auflisten, die dem Kursleiter zugeordnet sind, der im Kursleitersteuerelement 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 Steuerelement für Fehlermeldungen 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 Unterauswahlbefehl, der alle zugeordneten Person Entitäten aus der Navigationseigenschaft Course einer People Entität abruft und die Course Entität nur auswählt, wenn eine der zugehörigen Person Entitäten den ausgewählten PersonID Wert enthält.

Fügen Sie zum Erstellen des GridView Steuerelements das folgende Markup unmittelbar nach dem CoursesEntityDataSource Steuerelement hinzu (vor dem schließenden </div> Tag):

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

Laden Sie die Seite.

Bild04

Wählen Sie einen Kursleiter aus, dem mindestens ein Kurs zugewiesen ist, und der Kurs oder die Kurse werden in der Liste angezeigt. (Hinweis: Obwohl das Datenbankschema mehrere Kurse zulässt, hat in den testdaten, die mit der Datenbank bereitgestellt werden, kein Kursleiter mehr als einen Kurs. Sie können der Datenbank selbst Kurse hinzufügen, indem Sie das Fenster "Server-Explorer " oder die CoursesAdd.aspx-Seite verwenden, die Sie in einem späteren Lernprogramm hinzufügen.)

Bild05

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 das folgende Markup in Instructors.aspx nach dem schließenden </div>-Tag hinzu. Stellen Sie sicher, dass Sie dieses Markup nach dem schließenden Div-Tag platzieren und 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 Eigenschaft Where wählt einen Kurs anhand des Werts CourseID der ausgewählten Zeile im Steuerelement GridView aus. Das Markup gibt einen Handler für das Selected Ereignis an, den Sie später zum Anzeigen der Noten von Kursteilnehmern verwenden, was eine weitere Ebene niedriger in der Hierarchie ist.

Erstellen Sie in Instructors.aspx.cs den folgenden Stub für die Methode CourseDetailsEntityDataSource_Selected. (Sie füllen diesen Stub später im Lernprogramm aus. Sie benötigen ihn jetzt, damit die Seite kompiliert und ausgeführt wird.)

protected void CourseDetailsEntityDataSource_Selected(object sender, EntityDataSourceSelectedEventArgs e)
{
}

Laden Sie die Seite.

Bild06

Zunächst gibt es keine Kursdetails, da kein Kurs ausgewählt ist. Wählen Sie einen Kursleiter aus, dem ein Kurs zugewiesen wurde, und wählen Sie dann einen Kurs aus, um die Details anzuzeigen.

Bild07

Schließlich möchten Sie alle registrierten Schüler und ihre Noten für den ausgewählten Kurs anzeigen. Dazu verwenden Sie das Selected Ereignis des EntityDataSource Steuerelements, das an den Kurs DetailsViewgebunden 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 databindiert haben. Das EmptyDataTemplate Element stellt eine Meldung bereit, die angezeigt werden soll, wenn kein Kurs ausgewählt ist – in diesem Fall gibt es keine Kursteilnehmer, die angezeigt werden sollen. Das LayoutTemplate Element erstellt eine HTML-Tabelle zum Anzeigen der Liste und gibt die ItemTemplate anzuzeigenden Spalten an. Die Schüler-ID und die Schülernote stammen aus der StudentGrade Entität, und der Schülername stammt aus der Person Entität, die das Entity Framework in der Person Navigationseigenschaft der StudentGrade Entität verfügbar macht.

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 aufweisen, 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 die Entitäten aus der Navigationseigenschaft StudentGrade abgerufen, in eine Auflistung konvertiert und das Steuerelement GradesListView an die Auflistung gebunden.

Dies reicht aus, um Noten anzuzeigen, aber Sie möchten sicherstellen, dass die Nachricht in der leeren Datenvorlage beim ersten Anzeigen der Seite angezeigt wird und wann immer 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 aus der Page_Load Methode auf, um die leere Datenvorlage beim ersten Anzeigen der Seite anzuzeigen. Rufen Sie es aus der InstructorsGridView_SelectedIndexChanged Methode auf, da dieses Ereignis ausgelöst wird, wenn ein Kursleiter ausgewählt wird, was bedeutet, dass neue Kurse in das Kurssteuerelement GridView geladen werden und noch keine 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();
}

Laden Sie die Seite.

Bild08

Wählen Sie einen Kursleiter aus, dem ein Kurs zugewiesen ist, und wählen Sie dann den Kurs aus.

Bild09

Sie haben nun einige Möglichkeiten zum Arbeiten mit verwandten Daten gesehen. Im folgenden Lernprogramm 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.