Примечание
Для доступа к этой странице требуется авторизация. Вы можете попробовать войти или изменить каталоги.
Для доступа к этой странице требуется авторизация. Вы можете попробовать изменить каталоги.
Пример веб-приложения Contoso University демонстрирует создание ASP.NET Web Forms приложений с помощью Entity Framework 4.0 и Visual Studio 2010. Сведения о серии учебников см. в первом руководстве серии
Работа со связанными данными
В предыдущем руководстве EntityDataSource
вы использовали элемент управления для фильтрации, сортировки и группировки данных. В этом руководстве вы будете отображать и обновлять связанные данные.
Вы создадите страницу Преподаватели со списком преподавателей. При выборе преподавателя отображается список курсов, преподаваемых этим инструктором. При выборе курса вы увидите сведения о курсе и список учащихся, зачисленных на курс. Вы можете изменить имя преподавателя, дату найма и назначение в офисе. Назначение office — это отдельный набор сущностей, доступ к которому осуществляется через свойство навигации.
Вы можете связать данные master с подробными данными в разметке или коде. В этой части учебника вы будете использовать оба метода.
Отображение и обновление связанных сущностей в элементе управления GridView
Создайте новую веб-страницу с именем Instructors.aspx, которая использует страницу master Site.Master, и добавьте следующую разметку в Content
элемент управления с именем 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>
Эта разметка создает элемент EntityDataSource
управления, который выбирает инструкторов и включает обновления. Элемент div
настраивает разметку для отрисовки слева, чтобы позже можно было добавить столбец справа.
Между разметкой EntityDataSource
и закрывающим </div>
тегом добавьте следующую GridView
разметку, которая создает элемент управления и Label
элемент управления, который будет использоваться для сообщений об ошибках:
<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>
Этот GridView
элемент управления включает выбор строк, выделяет выделенную строку светло-серым цветом фона и задает обработчики (которые вы создадите позже) для SelectedIndexChanged
событий и Updating
. Он также указывает PersonID
для DataKeyNames
свойства , чтобы значение ключа выбранной строки можно было передать другому элементу управления, который вы добавите позже.
Последний столбец содержит задание инструктора, которое хранится в свойстве навигации сущности Person
, так как оно исходит от связанной сущности. Обратите внимание, что EditItemTemplate
элемент указывает Eval
вместо Bind
, так как GridView
элемент управления не может напрямую привязаться к свойствам навигации для их обновления. Вы обновите назначение office в коде. Для этого вам потребуется ссылка на TextBox
элемент управления, а затем вы получите и сохраните ее в событии TextBox
Init
элемента управления.
GridView
За элементом Label
управления следует элемент управления, который используется для сообщений об ошибках. Свойство элемента управления Visible
имеет значение false
, а состояние представления отключено, поэтому метка будет отображаться только в том случае, если код делает ее видимой в ответ на ошибку.
Откройте файл Instructors.aspx.cs и добавьте следующую using
инструкцию:
using ContosoUniversity.DAL;
Добавьте поле частного класса сразу после объявления имени разделяемого класса, чтобы содержать ссылку на текстовое поле назначения office.
private TextBox instructorOfficeTextBox;
Добавьте заглушку для обработчика SelectedIndexChanged
событий, которую вы добавите в дальнейшем. Кроме того, добавьте обработчик для события элемента управления Init
назначением TextBox
office, чтобы можно было сохранить ссылку TextBox
на элемент управления. Эта ссылка используется для получения значения, введенного пользователем, чтобы обновить сущность, связанную со свойством навигации.
protected void InstructorsGridView_SelectedIndexChanged(object sender, EventArgs e)
{
}
protected void InstructorOfficeTextBox_Init(object sender, EventArgs e)
{
instructorOfficeTextBox = sender as TextBox;
}
Событие элемента управления Updating
используется GridView
для обновления Location
свойства связанной OfficeAssignment
сущности. Добавьте следующий обработчик для Updating
события:
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.
}
}
}
Этот код выполняется, когда пользователь нажимает кнопку Обновить в строке GridView
. Код использует LINQ to Entities для получения сущностиOfficeAssignment
, связанной с текущей Person
сущностью, с помощью PersonID
выбранной строки из аргумента event.
Затем код выполняет одно из следующих действий в зависимости от значения в элементе InstructorOfficeTextBox
управления :
- Если текстовое поле содержит значение и сущность для обновления отсутствует
OfficeAssignment
, оно создает его. - Если текстовое поле содержит значение и есть
OfficeAssignment
сущность, оно обновляетLocation
значение свойства. - Если текстовое поле пусто и
OfficeAssignment
сущность существует, сущность удаляется.
После этого изменения сохраняются в базе данных. При возникновении исключения отображается сообщение об ошибке.
Запустите страницу.
Щелкните Изменить , и все поля будут изменены на текстовые поля.
Измените любое из этих значений, включая назначение Office. Нажмите кнопку Обновить , и вы увидите изменения, отраженные в списке.
Отображение связанных сущностей в отдельном элементе управления
Каждый преподаватель может преподавать один или несколько курсов, поэтому вы добавите EntityDataSource
элемент управления и GridView
элемент управления для перечисления курсов, связанных с тем или иным преподавателем, выбранным в элементе управления "Преподаватели GridView
". Чтобы создать заголовок и EntityDataSource
элемент управления для сущностей курсов, добавьте следующую разметку между элементом управления сообщением Label
об ошибке и закрывающим </div>
тегом:
<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>
Параметр Where
содержит значение преподавателя PersonID
, строка которого выбрана в элементе InstructorsGridView
управления . Свойство Where
содержит команду subselect, которая получает все связанные Person
сущности из Course
свойства навигации сущности People
Course
и выбирает сущность, только если одна из связанных Person
сущностей содержит выбранное PersonID
значение.
Чтобы создать GridView
элемент управления , добавьте следующую разметку CoursesEntityDataSource
сразу после элемента управления (перед закрывающим </div>
тегом):
<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>
Так как курсы не будут отображаться, если не выбран преподаватель, EmptyDataTemplate
включается элемент .
Запустите страницу.
Выберите преподавателя, которому назначен один или несколько курсов, и этот курс или курсы появятся в списке. (Примечание. Несмотря на то, что схема базы данных допускает несколько курсов, в тестовых данных, поставляемых с базой данных, ни один преподаватель на самом деле не имеет более одного курса. Вы можете самостоятельно добавлять курсы в базу данных с помощью окна Обозреватель сервера или страницы CoursesAdd.aspx, которые вы добавите в следующем руководстве.)
Элемент CoursesGridView
управления отображает только несколько полей курса. Чтобы отобразить все сведения о курсе, используйте DetailsView
элемент управления для выбранного пользователем курса. В Instructors.aspx добавьте следующую разметку после закрывающего </div>
тега (убедитесь, что эта разметка размещается после закрывающего тега div, а не перед ним):
<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>
Эта разметка создает элемент EntityDataSource
управления, привязанный к набору Courses
сущностей. Свойство Where
выбирает курс, используя CourseID
значение выбранной строки в элементе управления Courses GridView
. Разметка задает обработчик для Selected
события, который будет использоваться позже для отображения оценок учащихся, что является еще одним уровнем ниже в иерархии.
В файле Instructors.aspx.cs создайте следующую заглушку для CourseDetailsEntityDataSource_Selected
метода . (Вы заполните эту заглушку позже в руководстве. Пока она вам понадобится, чтобы страница скомпилирована и запущена.)
protected void CourseDetailsEntityDataSource_Selected(object sender, EntityDataSourceSelectedEventArgs e)
{
}
Запустите страницу.
Изначально нет сведений о курсе, так как курс не выбран. Выберите преподавателя, которому назначен курс, а затем выберите курс, чтобы просмотреть подробные сведения.
Использование события EntityDataSource "Selected" для отображения связанных данных
Наконец, необходимо отобразить всех зачисленных учащихся и их оценки для выбранного курса. Для этого используется Selected
событие элемента управления, EntityDataSource
привязанного к курсу DetailsView
.
В Instructors.aspx добавьте следующую разметку DetailsView
после элемента управления :
<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>
Эта разметка ListView
создает элемент управления, который отображает список учащихся и их оценки для выбранного курса. Источник данных не указан, так как вы будете привязыть данные к элементу управления в коде. Элемент EmptyDataTemplate
предоставляет сообщение для отображения, если курс не выбран. В этом случае учащиеся не отображаются. Элемент LayoutTemplate
создает таблицу HTML для отображения списка, а ItemTemplate
задает столбцы для отображения. Идентификатор учащегося и оценка учащегося относятся к StudentGrade
сущности, а имя учащегося — из Person
сущности, которую Entity Framework делает доступной в свойстве Person
навигации сущности StudentGrade
.
В Файле Instructors.aspx.cs замените метод stubbed-out CourseDetailsEntityDataSource_Selected
следующим кодом:
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();
}
}
Аргумент события для этого события предоставляет выбранные данные в виде коллекции, которая будет содержать ноль элементов, если ничего не выбрано, или один элемент, если выбрана Course
сущность. Если выбрана Course
сущность, код использует First
метод для преобразования коллекции в один объект. Затем он получает StudentGrade
сущности из свойства навигации, преобразует их в коллекцию и привязывает GradesListView
элемент управления к коллекции.
Этого достаточно для отображения оценок, но вы хотите убедиться, что сообщение в пустом шаблоне данных отображается при первом отображении страницы и всякий раз, когда курс не выбран. Для этого создайте следующий метод, который будет вызываться из двух мест:
private void ClearStudentGradesDataSource()
{
var emptyStudentGradesList = new List<StudentGrade>();
GradesListView.DataSource = emptyStudentGradesList;
GradesListView.DataBind();
}
Вызовите этот новый метод из метода , Page_Load
чтобы отобразить пустой шаблон данных при первом отображении страницы. И вызовите его из InstructorsGridView_SelectedIndexChanged
метода , так как это событие возникает при выборе преподавателя, что означает, что новые курсы загружаются в элемент управления курсами GridView
и пока не выбраны. Вот два вызова:
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
ClearStudentGradesDataSource();
}
}
protected void InstructorsGridView_SelectedIndexChanged(object sender, EventArgs e)
{
ClearStudentGradesDataSource();
}
Запустите страницу.
Выберите преподавателя, которому назначен курс, а затем выберите курс.
Теперь вы ознакомились с несколькими способами работы со связанными данными. В следующем руководстве вы узнаете, как добавить связи между существующими сущностями, как удалить связи и как добавить новую сущность, имеющую связь с существующей сущностью.