Introdução com o Entity Framework 4.0 Database First e ASP.NET 4 Web Forms – Parte 5
por Tom Dykstra
O aplicativo Web de exemplo da Contoso University demonstra como criar aplicativos ASP.NET Web Forms usando o Entity Framework 4.0 e o Visual Studio 2010. Para obter informações sobre a série de tutoriais, consulte o primeiro tutorial da série
Trabalhando com dados relacionados, continuado
No tutorial anterior, você começou a usar o EntityDataSource
controle para trabalhar com dados relacionados. Você exibiu vários níveis de hierarquia e editou dados em propriedades de navegação. Neste tutorial, você continuará trabalhando com dados relacionados adicionando e excluindo relações e adicionando uma nova entidade que tenha uma relação com uma entidade existente.
Você criará uma página que adiciona cursos atribuídos aos departamentos. Os departamentos já existem e, ao criar um novo curso, ao mesmo tempo, você estabelecerá uma relação entre ele e um departamento existente.
Você também criará uma página que funciona com uma relação muitos para muitos atribuindo um instrutor a um curso (adicionando uma relação entre duas entidades selecionadas) ou removendo um instrutor de um curso (removendo uma relação entre duas entidades selecionadas). No banco de dados, adicionar uma relação entre um instrutor e um curso resulta em uma nova linha sendo adicionada à CourseInstructor
tabela de associação; a remoção de uma relação envolve a exclusão de uma linha da CourseInstructor
tabela de associação. No entanto, você faz isso no Entity Framework definindo as propriedades de navegação, sem se referir explicitamente à CourseInstructor
tabela.
Adicionando uma entidade com uma relação a uma entidade existente
Crie uma nova página da Web chamada CoursesAdd.aspx que usa a página master Site.Master e adicione a seguinte marcação ao Content
controle chamado Content2
:
<h2>Add Courses</h2>
<asp:EntityDataSource ID="CoursesEntityDataSource" runat="server"
ContextTypeName="ContosoUniversity.DAL.SchoolEntities" EnableFlattening="False"
EntitySetName="Courses"
EnableInsert="True" EnableDelete="True" >
</asp:EntityDataSource>
<asp:DetailsView ID="CoursesDetailsView" runat="server" AutoGenerateRows="False"
DataSourceID="CoursesEntityDataSource" DataKeyNames="CourseID"
DefaultMode="Insert" oniteminserting="CoursesDetailsView_ItemInserting">
<Fields>
<asp:BoundField DataField="CourseID" HeaderText="ID" />
<asp:BoundField DataField="Title" HeaderText="Title" />
<asp:BoundField DataField="Credits" HeaderText="Credits" />
<asp:TemplateField HeaderText="Department">
<InsertItemTemplate>
<asp:EntityDataSource ID="DepartmentsEntityDataSource" runat="server" ConnectionString="name=SchoolEntities"
DefaultContainerName="SchoolEntities" EnableDelete="True" EnableFlattening="False"
EntitySetName="Departments" EntityTypeFilter="Department">
</asp:EntityDataSource>
<asp:DropDownList ID="DepartmentsDropDownList" runat="server" DataSourceID="DepartmentsEntityDataSource"
DataTextField="Name" DataValueField="DepartmentID"
oninit="DepartmentsDropDownList_Init">
</asp:DropDownList>
</InsertItemTemplate>
</asp:TemplateField>
<asp:CommandField ShowInsertButton="True" />
</Fields>
</asp:DetailsView>
Essa marcação cria um EntityDataSource
controle que seleciona cursos, que permite a inserção e que especifica um manipulador para o Inserting
evento. Você usará o manipulador para atualizar a Department
propriedade de navegação quando uma nova Course
entidade for criada.
A marcação também cria um DetailsView
controle a ser usado para adicionar novas Course
entidades. A marcação usa campos associados para Course
propriedades de entidade. Você precisa inserir o CourseID
valor porque este não é um campo de ID gerado pelo sistema. Em vez disso, é um número de curso que deve ser especificado manualmente quando o curso é criado.
Você usa um campo de modelo para a propriedade de navegação porque as Department
propriedades de navegação não podem ser usadas com BoundField
controles. O campo de modelo fornece uma lista suspensa para selecionar o departamento. A lista suspensa está associada à Departments
entidade definida usando Eval
em vez de Bind
, novamente porque você não pode associar diretamente as propriedades de navegação para atualizá-las. Especifique um manipulador para o DropDownList
evento do Init
controle para que você possa armazenar uma referência ao controle para uso pelo código que atualiza a DepartmentID
chave estrangeira.
Em CoursesAdd.aspx.cs logo após a declaração de classe parcial, adicione um campo de classe para manter uma referência ao DepartmentsDropDownList
controle:
private DropDownList departmentDropDownList;
Adicione um manipulador para o DepartmentsDropDownList
evento do Init
controle para que você possa armazenar uma referência ao controle. Isso permite obter o valor que o usuário inseriu e usá-lo para atualizar o DepartmentID
valor da Course
entidade.
protected void DepartmentsDropDownList_Init(object sender, EventArgs e)
{
departmentDropDownList = sender as DropDownList;
}
Adicione um manipulador para o DetailsView
evento do Inserting
controle:
protected void CoursesDetailsView_ItemInserting(object sender, DetailsViewInsertEventArgs e)
{
var departmentID = Convert.ToInt32(departmentDropDownList.SelectedValue);
e.Values["DepartmentID"] = departmentID;
}
Quando o usuário clica Insert
em , o Inserting
evento é gerado antes que o novo registro seja inserido. O código no manipulador obtém o DepartmentID
do controle e o DropDownList
usa para definir o valor que será usado para a DepartmentID
propriedade da Course
entidade.
O Entity Framework cuidará de adicionar este curso à Courses
propriedade de navegação da entidade associada Department
. Ele também adiciona o departamento à Department
propriedade de navegação da Course
entidade.
Execute a página.
Insira uma ID, um título, vários créditos e selecione um departamento e clique em Inserir.
Execute a página Courses.aspx e selecione o mesmo departamento para ver o novo curso.
Trabalhando com relações muitos para muitos
A relação entre o Courses
conjunto de entidades e o People
conjunto de entidades é uma relação muitos para muitos. Uma Course
entidade tem uma propriedade de navegação chamada People
que pode conter zero, uma ou mais entidades relacionadas Person
(representando instrutores atribuídos para ensinar esse curso). E uma Person
entidade tem uma propriedade de navegação chamada Courses
que pode conter zero, uma ou mais entidades relacionadas Course
(representando cursos que o instrutor é atribuído para ensinar). Um instrutor pode ministrar vários cursos, e um curso pode ser ministrado por vários instrutores. Nesta seção do passo a passo, você adicionará e removerá relações entre Person
entidades e Course
atualizando as propriedades de navegação das entidades relacionadas.
Crie uma nova página da Web chamada InstructorsCourses.aspx que usa a página master Site.Master e adicione a seguinte marcação ao Content
controle chamado Content2
:
<h2>Assign Instructors to Courses or Remove from Courses</h2>
<br />
<asp:EntityDataSource ID="InstructorsEntityDataSource" runat="server"
ContextTypeName="ContosoUniversity.DAL.SchoolEntities" EnableFlattening="False"
EntitySetName="People"
Where="it.HireDate is not null" Select="it.LastName + ', ' + it.FirstMidName AS Name, it.PersonID">
</asp:EntityDataSource>
Select an Instructor:
<asp:DropDownList ID="InstructorsDropDownList" runat="server" DataSourceID="InstructorsEntityDataSource"
AutoPostBack="true" DataTextField="Name" DataValueField="PersonID"
OnSelectedIndexChanged="InstructorsDropDownList_SelectedIndexChanged"
OnDataBound="InstructorsDropDownList_DataBound">
</asp:DropDownList>
<h3>
Assign a Course</h3>
<br />
Select a Course:
<asp:DropDownList ID="UnassignedCoursesDropDownList" runat="server"
DataTextField="Title" DataValueField="CourseID">
</asp:DropDownList>
<br />
<asp:Button ID="AssignCourseButton" runat="server" Text="Assign" OnClick="AssignCourseButton_Click" />
<br />
<asp:Label ID="CourseAssignedLabel" runat="server" Visible="false" Text="Assignment successful"></asp:Label>
<br />
<h3>
Remove a Course</h3>
<br />
Select a Course:
<asp:DropDownList ID="AssignedCoursesDropDownList" runat="server"
DataTextField="title" DataValueField="courseiD">
</asp:DropDownList>
<br />
<asp:Button ID="RemoveCourseButton" runat="server" Text="Remove" OnClick="RemoveCourseButton_Click" />
<br />
<asp:Label ID="CourseRemovedLabel" runat="server" Visible="false" Text="Removal successful"></asp:Label>
Essa marcação cria um EntityDataSource
controle que recupera o nome e PersonID
as entidades para Person
instrutores. Um DropDrownList
controle está associado ao EntityDataSource
controle . O DropDownList
controle especifica um manipulador para o DataBound
evento. Você usará esse manipulador para associar dados às duas listas suspensas que exibem cursos.
A marcação também cria o seguinte grupo de controles a ser usado para atribuir um curso ao instrutor selecionado:
- Um
DropDownList
controle para selecionar um curso a ser atribuído. Esse controle será preenchido com cursos que atualmente não estão atribuídos ao instrutor selecionado. - Um
Button
controle para iniciar a atribuição. - Um
Label
controle para exibir uma mensagem de erro se a atribuição falhar.
Por fim, a marcação também cria um grupo de controles a serem usados para remover um curso do instrutor selecionado.
Em InstructorsCourses.aspx.cs, adicione uma instrução using:
using ContosoUniversity.DAL;
Adicione um método para preencher as duas listas suspensas que exibem cursos:
private void PopulateDropDownLists()
{
using (var context = new SchoolEntities())
{
var allCourses = (from c in context.Courses
select c).ToList();
var instructorID = Convert.ToInt32(InstructorsDropDownList.SelectedValue);
var instructor = (from p in context.People.Include("Courses")
where p.PersonID == instructorID
select p).First();
var assignedCourses = instructor.Courses.ToList();
var unassignedCourses = allCourses.Except(assignedCourses.AsEnumerable()).ToList();
UnassignedCoursesDropDownList.DataSource = unassignedCourses;
UnassignedCoursesDropDownList.DataBind();
UnassignedCoursesDropDownList.Visible = true;
AssignedCoursesDropDownList.DataSource = assignedCourses;
AssignedCoursesDropDownList.DataBind();
AssignedCoursesDropDownList.Visible = true;
}
}
Esse código obtém todos os cursos do Courses
conjunto de entidades e obtém os cursos da propriedade de Courses
navegação da Person
entidade para o instrutor selecionado. Em seguida, ele determina quais cursos são atribuídos a esse instrutor e preenche as listas suspensas adequadamente.
Adicione um manipulador para o Assign
evento do Click
botão:
protected void AssignCourseButton_Click(object sender, EventArgs e)
{
using (var context = new SchoolEntities())
{
var instructorID = Convert.ToInt32(InstructorsDropDownList.SelectedValue);
var instructor = (from p in context.People
where p.PersonID == instructorID
select p).First();
var courseID = Convert.ToInt32(UnassignedCoursesDropDownList.SelectedValue);
var course = (from c in context.Courses
where c.CourseID == courseID
select c).First();
instructor.Courses.Add(course);
try
{
context.SaveChanges();
PopulateDropDownLists();
CourseAssignedLabel.Text = "Assignment successful.";
}
catch (Exception)
{
CourseAssignedLabel.Text = "Assignment unsuccessful.";
//Add code to log the error.
}
CourseAssignedLabel.Visible = true;
}
}
Esse código obtém a Person
entidade do instrutor selecionado, obtém a Course
entidade do curso selecionado e adiciona o curso selecionado à Courses
propriedade de navegação da entidade do Person
instrutor. Em seguida, ele salva as alterações no banco de dados e preenche novamente as listas suspensas para que os resultados possam ser vistos imediatamente.
Adicione um manipulador para o Remove
evento do Click
botão:
protected void RemoveCourseButton_Click(object sender, EventArgs e)
{
using (var context = new SchoolEntities())
{
var instructorID = Convert.ToInt32(InstructorsDropDownList.SelectedValue);
var instructor = (from p in context.People
where p.PersonID == instructorID
select p).First();
var courseID = Convert.ToInt32(AssignedCoursesDropDownList.SelectedValue);
var courses = instructor.Courses;
var courseToRemove = new Course();
foreach (Course c in courses)
{
if (c.CourseID == courseID)
{
courseToRemove = c;
break;
}
}
try
{
courses.Remove(courseToRemove);
context.SaveChanges();
PopulateDropDownLists();
CourseRemovedLabel.Text = "Removal successful.";
}
catch (Exception)
{
CourseRemovedLabel.Text = "Removal unsuccessful.";
//Add code to log the error.
}
CourseRemovedLabel.Visible = true;
}
}
Esse código obtém a Person
entidade do instrutor selecionado, obtém a Course
entidade do curso selecionado e remove o curso selecionado da propriedade de Person
navegação da Courses
entidade. Em seguida, ele salva as alterações no banco de dados e preenche novamente as listas suspensas para que os resultados possam ser vistos imediatamente.
Adicione código Page_Load
ao método que garante que as mensagens de erro não estejam visíveis quando não houver erro para relatar e adicione manipuladores para os DataBound
eventos e SelectedIndexChanged
da lista suspensa de instrutores para preencher as listas suspensas de cursos:
protected void Page_Load(object sender, EventArgs e)
{
CourseAssignedLabel.Visible = false;
CourseRemovedLabel.Visible = false;
}
protected void InstructorsDropDownList_DataBound(object sender, EventArgs e)
{
PopulateDropDownLists();
}
protected void InstructorsDropDownList_SelectedIndexChanged(object sender, EventArgs e)
{
PopulateDropDownLists();
}
Execute a página.
Selecione um instrutor. A lista suspensa Atribuir um Curso exibe os cursos aos quais o instrutor não ensina e a lista suspensa Remover um Curso exibe os cursos aos quais o instrutor já está atribuído. Na seção Atribuir um Curso , selecione um curso e clique em Atribuir. O curso passa para a lista suspensa Remover um Curso . Selecione um curso na seção Remover um Curso e clique em Remover. O curso passa para a lista suspensa Atribuir um Curso .
Agora você viu mais algumas maneiras de trabalhar com dados relacionados. No tutorial a seguir, você aprenderá a usar a herança no modelo de dados para melhorar a manutenção do aplicativo.