Začínáme s Entity Framework 4.0 Database First a ASP.NET 4 Web Forms – část 4
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ě.
Práce se souvisejícími daty
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.
Zobrazení a aktualizace souvisejících entit v ovládacím prvku GridView
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 Content2
ná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 false
a 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
, aktualizujeLocation
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.
Klikněte na Upravit a všechna pole se změní na textová pole.
Změňte kteroukoli z těchto hodnot, včetně přiřazení Office. Klikněte na Aktualizovat a změny se projeví v seznamu.
Zobrazení souvisejících entit v samostatném ovládacím prvku
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 Course
PersonID
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.
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.)
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.
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.
Použití události Selected entityDataSource k zobrazení souvisejících dat
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.
Vyberte instruktora, který má přiřazený kurz, a pak vyberte kurz.
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ě.