Freigeben über


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.

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.

Image01

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 Content2hinzu:

<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 BindangibtEval, 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 TextBoxInit 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 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 an der Datenbank gespeichert. Wenn eine Ausnahme auftritt, wird eine Fehlermeldung angezeigt.

Führen Sie die Seite aus.

Image02

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

Image03

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

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.

Image04

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

Image05

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.

Abbildung06

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.

Image07

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

Image08

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

Image09

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.