Sdílet prostřednictvím


Začínáme s Entity Framework 4.0 Database First a ASP.NET 4 Web Forms – část 4

Tom Dykstra

Ukázková webová aplikace Contoso University ukazuje, jak vytvářet ASP.NET Web Forms aplikace pomocí entity Framework 4.0 a sady Visual Studio 2010. Informace o této sérii kurzů najdete v prvním kurzu v této řadě.

V předchozím kurzu jste ovládací prvek použili EntityDataSource k filtrování, řazení a seskupení dat. V tomto kurzu zobrazíte a aktualizujete související data.

Vytvoříte stránku Instruktoři, která zobrazuje seznam instruktorů. Když vyberete instruktora, zobrazí se seznam kurzů, které tento instruktor vyučuje. Když vyberete kurz, zobrazí se podrobnosti o kurzu a seznam studentů, kteří se do kurzu zapsali. Můžete upravit jméno instruktora, datum nástupu a přiřazení kanceláře. Přiřazení kanceláře je samostatná sada entit, ke které přistupujete prostřednictvím navigační vlastnosti.

Hlavní data můžete propojit s podrobnými daty ve značkách nebo v kódu. V této části kurzu použijete obě metody.

Obrázek 01

Vytvořte novou webovou stránku s názvem Instructors.aspx , která používá stránku předlohy Site.Master , a přidejte do Content ovládacího prvku s názvem Content2následující kód:

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

Tento kód vytvoří ovládací prvek EntityDataSource , který vybere instruktory a povolí aktualizace. Element div nakonfiguruje revize tak, aby se vykreslovali na levé straně, abyste později mohli přidat sloupec vpravo.

Mezi značky značky EntityDataSource a uzavírací </div> značky přidejte následující kód, který vytvoří GridView ovládací prvek a Label ovládací prvek, který použijete pro chybové zprávy:

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

Tento GridView ovládací prvek povolí výběr řádku, zvýrazní vybraný řádek světle šedou barvou pozadí a určí obslužné rutiny (které vytvoříte později) pro SelectedIndexChanged události a Updating . Určuje také PersonID vlastnost DataKeyNames , aby se hodnota klíče vybraného řádku předala jinému ovládacímu prvku, který přidáte později.

Poslední sloupec obsahuje přiřazení kanceláře instruktora, které je uloženo ve vlastnosti Person navigace entity, protože pochází z přidružené entity. Všimněte si, že EditItemTemplate element určuje Eval místo Bind, protože GridView ovládací prvek nemůže přímo svázat s navigačními vlastnostmi, aby je mohl aktualizovat. Přiřazení kanceláře aktualizujete v kódu. K tomu budete potřebovat odkaz na TextBox ovládací prvek, který získáte a uložíte v TextBox události ovládacího prvku Init .

GridView Následující ovládací prvek je ovládací prvekLabel, který se používá pro chybové zprávy. Vlastnost ovládacího prvku Visible je falsea stav zobrazení je vypnutý, takže popisek se zobrazí pouze v případě, že ho kód zviditelní v reakci na chybu.

Otevřete soubor Instructors.aspx.cs a přidejte následující using příkaz:

using ContosoUniversity.DAL;

Bezprostředně za deklaraci názvu částečné třídy přidejte pole soukromé třídy, které bude obsahovat odkaz na textové pole přiřazení kanceláře.

private TextBox instructorOfficeTextBox;

Přidejte zástupný kód pro obslužnou rutinu SelectedIndexChanged události, kterou přidáte později. Přidejte také obslužnou rutinu pro událost ovládacího prvku Init přiřazení TextBox office, abyste mohli uložit odkaz na TextBox ovládací prvek. Tento odkaz použijete k získání hodnoty, kterou uživatel zadal, aby mohl aktualizovat entitu přidruženou k navigační vlastnosti.

protected void InstructorsGridView_SelectedIndexChanged(object sender, EventArgs e)
{
}

protected void InstructorOfficeTextBox_Init(object sender, EventArgs e)
{
    instructorOfficeTextBox = sender as TextBox;
}

Událost ovládacího prvku Updating použijete GridView k aktualizaci Location vlastnosti přidružené OfficeAssignment entity. Přidejte následující obslužnou rutinu Updating události:

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

Tento kód se spustí, když uživatel klikne na Aktualizovat na řádku GridView . Kód pomocí LINQ to Entities načte entitu OfficeAssignment přidruženou k aktuální Person entitě pomocí PersonID z vybraného řádku z argumentu události.

Kód pak provede jednu z následujících akcí v závislosti na hodnotě v ovládacím InstructorOfficeTextBox prvku:

  • Pokud má textové pole hodnotu a neexistuje žádná OfficeAssignment entita, kterou by bylo možné aktualizovat, vytvoří ji.
  • Pokud textové pole obsahuje hodnotu a existuje entita OfficeAssignment , aktualizuje Location se hodnota vlastnosti.
  • Pokud je textové pole prázdné a entita OfficeAssignment existuje, entita se odstraní.

Poté uloží změny do databáze. Pokud dojde k výjimce, zobrazí se chybová zpráva.

Spusťte stránku.

Obrázek 02

Klikněte na Upravit a všechna pole se změní na textová pole.

Obrázek 03

Změňte kteroukoli z těchto hodnot, včetně přiřazení Office. Klikněte na Aktualizovat a změny se projeví v seznamu.

Každý instruktor může vyučovat jeden nebo více kurzů, takže přidáte EntityDataSource ovládací prvek a GridView ovládací prvek pro výpis kurzů přidružených ke kterémukoli instruktorovi, který je vybraný v ovládacím prvku instruktorů GridView . Pokud chcete vytvořit nadpis a EntityDataSource ovládací prvek pro entity kurzů, přidejte mezi ovládací prvek chybové zprávy Label a uzavírací </div> značku následující kód:

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

Parametr Where obsahuje hodnotu PersonID instruktora, jehož řádek je vybrán v ovládacím InstructorsGridView prvku. Vlastnost Where obsahuje příkaz dílčího výběru, který získá všechny přidružené Person entity z navigační vlastnosti entity People a vybere entitu Course pouze v případě, že jedna z přidružených Person entit obsahuje vybranou CoursePersonID hodnotu.

Pokud chcete vytvořit GridView ovládací prvek, přidejte následující kód bezprostředně za ovládací CoursesEntityDataSource prvek (před uzavírací </div> značku):

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

Vzhledem k tomu, že se nezobrazí žádné kurzy, pokud není vybraný žádný instruktor, je zahrnutý prvek EmptyDataTemplate .

Spusťte stránku.

Obrázek 04

Vyberte instruktora, který má přiřazený jeden nebo více kurzů, a kurz nebo kurzy se zobrazí v seznamu. (Poznámka: Přestože schéma databáze umožňuje více kurzů, v testovacích datech dodaných s databází nemá žádný instruktor ve skutečnosti více než jeden kurz. Kurzy můžete do databáze přidat sami pomocí okna Průzkumníka serveru nebo stránky CoursesAdd.aspx , kterou přidáte v pozdějším kurzu.)

Obrázek 05

Ovládací CoursesGridView prvek zobrazuje jenom několik polí kurzu. Pokud chcete zobrazit všechny podrobnosti kurzu, použijete DetailsView ovládací prvek pro kurz, který uživatel vybere. V instructors.aspx přidejte následující kód za uzavírací </div> značku (nezapomeňte tento kód umístit za uzavírací značku div, ne před ni):

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

Tento kód vytvoří ovládací prvek EntityDataSource , který je vázaný na Courses sadu entit. Vlastnost Where vybere kurz pomocí CourseID hodnoty vybraného řádku v ovládacím prvku courses GridView . Kód určuje obslužnou rutinu Selected události, kterou později použijete k zobrazení známek studentů, což je v hierarchii o další úroveň níže.

V souboru Instructors.aspx.cs vytvořte pro metodu CourseDetailsEntityDataSource_Selected následující zástupný kód. (Tuto zástupný kód vyplníte později v tomto kurzu; prozatím ji potřebujete, aby se stránka zkompiloval a spustil.)

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

Spusťte stránku.

Obrázek 06

Zpočátku nejsou k dispozici žádné podrobnosti o kurzu, protože není vybraný žádný kurz. Vyberte instruktora, který má přiřazený kurz, a pak výběrem kurzu zobrazte podrobnosti.

Obrázek 07

Nakonec chcete zobrazit všechny zaregistrované studenty a jejich známky pro vybraný kurz. K tomu použijete Selected událost ovládacího prvku vázaného EntityDataSource na kurz DetailsView.

V souboru Instructors.aspx přidejte za DetailsView ovládací prvek následující kód:

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

Tato revize vytvoří ListView ovládací prvek, který zobrazí seznam studentů a jejich známek pro vybraný kurz. Není zadaný žádný zdroj dat, protože ovládací prvek databindujete v kódu. Element EmptyDataTemplate poskytuje zprávu, která se zobrazí, když není vybraný žádný kurz – v takovém případě neexistují žádní studenti, které by bylo potřeba zobrazit. Element LayoutTemplate vytvoří tabulku HTML pro zobrazení seznamu a ItemTemplate určuje sloupce, které se mají zobrazit. ID studenta a známka studenta pocházejí z StudentGrade entity a jméno studenta pochází z Person entity, kterou Entity Framework zpřístupňuje ve Person vlastnosti StudentGrade navigace entity.

V souboru Instructors.aspx.cs nahraďte metodu stubbed-out CourseDetailsEntityDataSource_Selected následujícím kódem:

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();
    }
}

Argument události pro tuto událost poskytuje vybraná data ve formě kolekce, která nebude obsahovat žádnou položku, pokud není vybrána žádná položka, nebo jednu položku, pokud je vybrána entita Course . Pokud je vybrána Course entita, kód použije metodu First k převodu kolekce na jeden objekt. Potom získá StudentGrade entity z navigační vlastnosti, převede je na kolekci a vytvoří vazbu GradesListView ovládacího prvku na kolekci.

To stačí k zobrazení známek, ale chcete mít jistotu, že se zpráva v prázdné šabloně dat zobrazí při prvním zobrazení stránky a vždy, když není vybraný kurz. Uděláte to tak, že vytvoříte následující metodu, kterou budete volat ze dvou míst:

private void ClearStudentGradesDataSource()
{
    var emptyStudentGradesList = new List<StudentGrade>();
    GradesListView.DataSource = emptyStudentGradesList;
    GradesListView.DataBind();
}

Voláním této nové metody z Page_Load metody zobrazíte prázdnou šablonu dat při prvním zobrazení stránky. A volejte ji z InstructorsGridView_SelectedIndexChanged metody, protože tato událost se vyvolá při výběru instruktora, což znamená, že se do řízení kurzů GridView načtou nové kurzy a zatím není vybrán žádný. Tady jsou dvě volání:

protected void Page_Load(object sender, EventArgs e)
{
    if (!IsPostBack)
    {
        ClearStudentGradesDataSource();                
    }
}
protected void InstructorsGridView_SelectedIndexChanged(object sender, EventArgs e)
{
    ClearStudentGradesDataSource();
}

Spusťte stránku.

Obrázek 08

Vyberte instruktora, který má přiřazený kurz, a pak vyberte kurz.

Obrázek 09

Teď jste viděli několik způsobů, jak pracovat se souvisejícími daty. V následujícím kurzu se dozvíte, jak přidat relace mezi existujícími entitami, jak odebrat relace a jak přidat novou entitu, která má vztah k existující entitě.