Partilhar via


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

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.

Captura de tela da janela Explorer da Internet, que mostra os campos de texto Adicionar Cursos com ID, Título e Créditos e uma lista suspensa Departamento.

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.

Captura de tela da janela Explorer da Internet, que mostra a exibição Atribuir Instrutores a Cursos ou Remover dos Cursos.

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

Captura de tela da janela Explorer da Internet, que mostra os campos de texto Adicionar Cursos com ID, Título e Créditos e uma lista suspensa Departamento.

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.

Imagem03

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.

Captura de tela da janela Explorer da Internet, que mostra a exibição Atribuir Instrutores a Cursos ou Remover de Cursos com as listas suspensas correspondentes.

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.