Introduzione con Entity Framework 4.0 Database First e ASP.NET 4 Web Forms - Parte 5

di Tom Dykstra

L'applicazione Web di esempio Contoso University illustra come creare applicazioni Web Forms ASP.NET usando Entity Framework 4.0 e Visual Studio 2010. Per informazioni sulla serie di esercitazioni, vedere la prima esercitazione della serie

Nell'esercitazione precedente è stato iniziato a usare il EntityDataSource controllo per lavorare con i dati correlati. Sono stati visualizzati più livelli di gerarchia e dati modificati nelle proprietà di navigazione. In questa esercitazione si continuerà a usare i dati correlati aggiungendo ed eliminando relazioni e aggiungendo una nuova entità con una relazione con un'entità esistente.

Verrà creata una pagina che aggiunge corsi assegnati ai reparti. I reparti esistono già e quando si crea un nuovo corso, contemporaneamente si stabilirà una relazione tra di esso e un reparto esistente.

Screenshot della finestra di Internet Explorer, che mostra i campi di testo Aggiungi corsi con ID, Titolo e Crediti e un elenco a discesa Reparto.

Si creerà anche una pagina che funziona con una relazione molti-a-molti assegnando un insegnante a un corso (aggiungendo una relazione tra due entità selezionate) o rimuovendo un insegnante da un corso (rimuovendo una relazione tra due entità selezionate). Nel database, l'aggiunta di una relazione tra un insegnante e un corso comporta l'aggiunta CourseInstructor di una nuova riga alla tabella di associazione. La rimozione di una relazione comporta l'eliminazione di una riga dalla tabella di CourseInstructor associazione. Tuttavia, questa operazione viene eseguita in Entity Framework impostando le proprietà di navigazione, senza fare riferimento alla CourseInstructor tabella in modo esplicito.

Screenshot della finestra di Internet Explorer, che mostra la visualizzazione Assegna insegnanti ai corsi o Rimuovi dai corsi.

Aggiunta di un'entità con una relazione a un'entità esistente

Creare una nuova pagina Web denominata CoursesAdd.aspx che usa la pagina master Site.Master e aggiungere il markup seguente al Content controllo denominato 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>

Questo markup crea un EntityDataSource controllo che seleziona i corsi, che consente l'inserimento e che specifica un gestore per l'evento Inserting . Si userà il gestore per aggiornare la Department proprietà di navigazione quando viene creata una nuova Course entità.

Il markup crea anche un DetailsView controllo da usare per l'aggiunta di nuove Course entità. Il markup usa campi associati per Course le proprietà dell'entità. È necessario immettere il CourseID valore perché non si tratta di un campo ID generato dal sistema. È invece un numero di corso che deve essere specificato manualmente al momento della creazione del corso.

Utilizzare un campo modello per la Department proprietà di navigazione perché le proprietà di navigazione non possono essere utilizzate con BoundField i controlli. Il campo modello fornisce un elenco a discesa per selezionare il reparto. L'elenco a discesa è associato al Departments set di entità utilizzando Eval anziché Bind, anche in questo caso perché non è possibile associare direttamente le proprietà di navigazione per aggiornarle. Specificare un gestore per l'evento DropDownList del Init controllo in modo che sia possibile archiviare un riferimento al controllo da utilizzare dal codice che aggiorna la DepartmentID chiave esterna.

In CoursesAdd.aspx.cs subito dopo la dichiarazione di classe parziale aggiungere un campo classe per contenere un riferimento al DepartmentsDropDownList controllo:

private DropDownList departmentDropDownList;

Aggiungere un gestore per l'evento DepartmentsDropDownList del Init controllo in modo che sia possibile archiviare un riferimento al controllo. In questo modo è possibile ottenere il valore immesso dall'utente e usarlo per aggiornare il DepartmentID valore dell'entità Course .

protected void DepartmentsDropDownList_Init(object sender, EventArgs e)
{
    departmentDropDownList = sender as DropDownList;
}

Aggiungere un gestore per l'evento DetailsView del Inserting controllo:

protected void CoursesDetailsView_ItemInserting(object sender, DetailsViewInsertEventArgs e)
{
    var departmentID = Convert.ToInt32(departmentDropDownList.SelectedValue);
    e.Values["DepartmentID"] = departmentID;
}

Quando l'utente fa clic su Insert, l'evento viene generato prima dell'inserimento Inserting del nuovo record. Il codice nel gestore ottiene l'oggetto DepartmentID dal DropDownList controllo e lo usa per impostare il valore che verrà usato per la DepartmentID proprietà dell'entità Course .

Entity Framework si occuperà dell'aggiunta di questo corso alla Courses proprietà di navigazione dell'entità associata Department . Aggiunge anche il reparto alla Department proprietà di navigazione dell'entità Course .

Eseguire la pagina.

Screenshot della finestra di Internet Explorer, che mostra i campi di testo Aggiungi corsi con ID, Titolo e Crediti e un elenco a discesa Reparto.

Immettere un ID, un titolo, un numero di crediti e selezionare un reparto, quindi fare clic su Inserisci.

Eseguire la pagina Courses.aspx e selezionare lo stesso reparto per visualizzare il nuovo corso.

Immagine03

Utilizzo delle relazioni molti-a-molti

La relazione tra il Courses set di entità e il People set di entità è una relazione molti-a-molti. Un'entità Course ha una proprietà di navigazione denominata People che può contenere zero, una o più entità correlate Person (che rappresentano gli insegnanti assegnati per insegnare tale corso). Person Un'entità ha una proprietà di navigazione denominata Courses che può contenere zero, una o più entità correlate Course (che rappresenta i corsi assegnati all'insegnante per l'insegnamento). Un insegnante potrebbe insegnare più corsi e un corso potrebbe essere insegnato da più insegnanti. In questa sezione della procedura dettagliata verranno aggiunte e rimosse le relazioni tra Person le entità e Course aggiornando le proprietà di navigazione delle entità correlate.

Creare una nuova pagina Web denominata InstructorsCourses.aspx che usa la pagina master Site.Master e aggiungere il markup seguente al Content controllo denominato 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>

Questo markup crea un EntityDataSource controllo che recupera il nome e PersonID le Person entità per gli istruttori. Un DropDrownList controllo è associato al EntityDataSource controllo . Il DropDownList controllo specifica un gestore per l'evento DataBound . Questo gestore verrà usato per associare i due elenchi a discesa che visualizzano i corsi.

Il markup crea anche il gruppo di controlli seguente da usare per assegnare un corso all'insegnante selezionato:

  • Controllo DropDownList per la selezione di un corso da assegnare. Questo controllo verrà popolato con corsi attualmente non assegnati all'insegnante selezionato.
  • Controllo Button per avviare l'assegnazione.
  • Controllo Label per visualizzare un messaggio di errore se l'assegnazione non riesce.

Infine, il markup crea anche un gruppo di controlli da usare per rimuovere un corso dall'insegnante selezionato.

In InstructorsCourses.aspx.cs aggiungere un'istruzione using:

using ContosoUniversity.DAL;

Aggiungere un metodo per popolare i due elenchi a discesa che visualizzano i corsi:

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

Questo codice ottiene tutti i corsi dal Courses set di entità e ottiene i corsi dalla Courses proprietà di navigazione dell'entità per l'insegnante Person selezionato. Determina quindi i corsi assegnati a tale insegnante e popola gli elenchi a discesa di conseguenza.

Aggiungere un gestore per l'evento Assign del Click pulsante:

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

Questo codice ottiene l'entità Person per l'insegnante selezionato, ottiene l'entità Course per il corso selezionato e aggiunge il corso selezionato alla Courses proprietà di navigazione dell'entità dell'insegnante Person . Salva quindi le modifiche al database e ripopola gli elenchi a discesa in modo che i risultati possano essere visualizzati immediatamente.

Aggiungere un gestore per l'evento Remove del Click pulsante:

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

Questo codice ottiene l'entità Person per l'insegnante selezionato, ottiene l'entità Course per il corso selezionato e rimuove il corso selezionato dalla Person proprietà di navigazione dell'entità Courses . Salva quindi le modifiche al database e ripopola gli elenchi a discesa in modo che i risultati possano essere visualizzati immediatamente.

Aggiungere codice al Page_Load metodo che assicura che i messaggi di errore non siano visibili quando non è presente alcun errore da segnalare e aggiungere gestori per gli DataBound eventi e SelectedIndexChanged dell'elenco a discesa degli insegnanti per popolare gli elenchi a discesa dei corsi:

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

Eseguire la pagina.

Screenshot della finestra di Internet Explorer, che mostra l'elenco a discesa Assegna istruttori ai corsi o Rimuovi da corsi con i corrispondenti elenchi a discesa.

Selezionare un insegnante. L'elenco a discesa Assegna un corso visualizza i corsi a cui l'insegnante non insegna e nell'elenco a discesa Rimuovi un corso vengono visualizzati i corsi a cui l'insegnante è già assegnato. Nella sezione Assegna un corso selezionare un corso e quindi fare clic su Assegna. Il corso passa all'elenco a discesa Rimuovi un corso . Selezionare un corso nella sezione Rimuovi un corso e fare clic su Rimuovi. Il corso passa all'elenco a discesa Assegna un corso .

Sono stati ora illustrati altri modi per lavorare con i dati correlati. Nell'esercitazione seguente si apprenderà come usare l'ereditarietà nel modello di dati per migliorare la gestibilità dell'applicazione.