Condividi tramite


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

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 nella serie

Nell'esercitazione precedente è stato usato il EntityDataSource controllo per filtrare, ordinare e raggruppare i dati. In questa esercitazione verranno visualizzati e aggiornati i dati correlati.

Verrà creata la pagina Insegnanti che mostra un elenco di insegnanti. Quando si seleziona un insegnante, viene visualizzato un elenco di corsi insegnati da tale insegnante. Quando si seleziona un corso, vengono visualizzati i dettagli per il corso e un elenco di studenti iscritti al corso. È possibile modificare il nome dell'insegnante, la data di assunzione e l'assegnazione di ufficio. L'assegnazione di office è un set di entità separato a cui si accede tramite una proprietà di spostamento.

È possibile collegare i dati master ai dati di dettaglio nel markup o nel codice. In questa parte dell'esercitazione si useranno entrambi i metodi.

Immagine01

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

Questo markup crea un EntityDataSource controllo che seleziona gli insegnanti e abilita gli aggiornamenti. L'elemento div configura il markup per il rendering a sinistra in modo che sia possibile aggiungere una colonna a destra in un secondo momento.

Tra il markup e il EntityDataSource tag di chiusura </div> aggiungere il markup seguente che crea un GridView controllo e un Label controllo che verrà usato per i messaggi di errore:

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

Questo GridView controllo abilita la selezione delle righe, evidenzia la riga selezionata con un colore di sfondo grigio chiaro e specifica i gestori (che verranno creati in seguito) per gli SelectedIndexChanged eventi e Updating . Specifica PersonID anche per la DataKeyNames proprietà, in modo che il valore della chiave della riga selezionata possa essere passato a un altro controllo che verrà aggiunto in un secondo momento.

L'ultima colonna contiene l'assegnazione dell'ufficio dell'insegnante, archiviata in una proprietà di navigazione dell'entità perché proviene da un'entità Person associata. Si noti che l'elemento specifica Eval anziché Bind, perché il EditItemTemplateGridView controllo non può associare direttamente alle proprietà di spostamento per aggiornarle. L'assegnazione dell'ufficio verrà aggiornata nel codice. A tale scopo, è necessario un riferimento al TextBox controllo e si otterrà e si salverà tale elemento nell'evento TextBox del Init controllo.

Seguendo il GridView controllo è un Label controllo usato per i messaggi di errore. La proprietà del controllo è falsee lo stato di Visible visualizzazione viene disattivato, in modo che l'etichetta venga visualizzata solo quando il codice lo rende visibile in risposta a un errore.

Aprire il file Instructors.aspx.cs e aggiungere l'istruzione seguente using :

using ContosoUniversity.DAL;

Aggiungere un campo classe privata immediatamente dopo la dichiarazione di nome di classe parziale per contenere un riferimento alla casella di testo assegnazione di office.

private TextBox instructorOfficeTextBox;

Aggiungere uno stub per il SelectedIndexChanged gestore eventi per il quale si aggiungerà il codice per un secondo momento. Aggiungere anche un gestore per l'evento del Init controllo assegnazione TextBox di office in modo che sia possibile archiviare un riferimento al TextBox controllo. Questo riferimento verrà usato per ottenere il valore immesso dall'utente per aggiornare l'entità associata alla proprietà di spostamento.

protected void InstructorsGridView_SelectedIndexChanged(object sender, EventArgs e)
{
}

protected void InstructorOfficeTextBox_Init(object sender, EventArgs e)
{
    instructorOfficeTextBox = sender as TextBox;
}

Si userà l'evento GridView del Updating controllo per aggiornare la Location proprietà dell'entità associata OfficeAssignment . Aggiungere il gestore seguente per l'evento 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.
        }
    }
}

Questo codice viene eseguito quando l'utente fa clic su Aggiorna in una GridView riga. Il codice usa LINQ to Entities per recuperare l'entità OfficeAssignment associata all'entità corrente Person usando l'oggetto PersonID della riga selezionata dall'argomento evento.

Il codice esegue quindi una delle azioni seguenti a seconda del valore nel InstructorOfficeTextBox controllo:

  • Se la casella di testo ha un valore e non OfficeAssignment esiste un'entità da aggiornare, ne crea una.
  • Se la casella di testo ha un valore ed è presente un'entità OfficeAssignment , aggiorna il valore della Location proprietà.
  • Se la casella di testo è vuota e esiste un'entità OfficeAssignment , elimina l'entità.

In seguito, salva le modifiche apportate al database. Se si verifica un'eccezione, viene visualizzato un messaggio di errore.

Eseguire la pagina.

Immagine02

Fare clic su Modifica e tutti i campi cambiano nelle caselle di testo.

Immagine03

Modificare uno di questi valori, incluso l'assegnazione di Office. Fare clic su Aggiorna e verranno visualizzate le modifiche riflesse nell'elenco.

Ogni insegnante può insegnare uno o più corsi, quindi si aggiungerà un EntityDataSource controllo e un GridView controllo per elencare i corsi associati a qualsiasi insegnante selezionato nel controllo insegnanti GridView . Per creare un'intestazione e il EntityDataSource controllo per le entità corsi, aggiungere il markup seguente tra il controllo del messaggio Label di errore e il tag di chiusura </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>

Il Where parametro contiene il valore dell'insegnante PersonID la cui riga è selezionata nel InstructorsGridView controllo. La Where proprietà contiene un comando di selezione secondaria che ottiene tutte le entità associate dalla proprietà di spostamento di People un'entità Course e seleziona l'entità solo se una delle entità associate PersonPerson contiene il Course valore selezionatoPersonID.

Per creare il GridView controllo., aggiungere il markup seguente immediatamente dopo il CoursesEntityDataSource controllo (prima del tag di chiusura </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>

Poiché non verranno visualizzati corsi se non è selezionato alcun insegnante, è incluso un EmptyDataTemplate elemento.

Eseguire la pagina.

Immagine04

Selezionare un insegnante che ha uno o più corsi assegnati e i corsi vengono visualizzati nell'elenco. Nota: anche se lo schema del database consente più corsi, nei dati di test forniti con il database non è effettivamente disponibile più corsi. È possibile aggiungere corsi al database usando la finestra Esplora server o la pagina CoursesAdd.aspx , che verrà aggiunta in un'esercitazione successiva.

Immagine05

Il CoursesGridView controllo mostra solo alcuni campi di corso. Per visualizzare tutti i dettagli per un corso, si userà un DetailsView controllo per il corso selezionato dall'utente. In Instructors.aspx aggiungere il markup seguente dopo il tag di chiusura (assicurarsi di posizionare questo markup dopo il tag div di chiusura</div>, non prima):

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

Questo markup crea un EntityDataSource controllo associato al Courses set di entità. La Where proprietà seleziona un corso usando il CourseID valore della riga selezionata nel controllo corsi GridView . Il markup specifica un gestore per l'evento Selected , che verrà usato più avanti per visualizzare i voti degli studenti, ovvero un altro livello inferiore nella gerarchia.

In Instructors.aspx.cs creare lo stub seguente per il CourseDetailsEntityDataSource_Selected metodo. Questo stub verrà compilato più avanti nell'esercitazione. Per il momento, è necessario in modo che la pagina venga compilata ed eseguita.

protected void CourseDetailsEntityDataSource_Selected(object sender, EntityDataSourceSelectedEventArgs e)
{
}

Eseguire la pagina.

Image06

Inizialmente non ci sono dettagli del corso perché non è selezionato alcun corso. Selezionare un insegnante che ha un corso assegnato e quindi selezionare un corso per visualizzare i dettagli.

Immagine07

Infine, vuoi mostrare tutti gli studenti iscritti e i loro voti per il corso selezionato. A tale scopo, si userà l'evento Selected del EntityDataSource controllo associato al corso DetailsView.

In Instructors.aspx aggiungere il markup seguente dopo il DetailsView controllo:

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

Questo markup crea un controllo che visualizza un ListView elenco di studenti e i relativi voti per il corso selezionato. Nessuna origine dati è specificata perché il controllo verrà risolto nel codice. L'elemento EmptyDataTemplate fornisce un messaggio da visualizzare quando non viene selezionato alcun corso, in questo caso non ci sono studenti da visualizzare. L'elemento LayoutTemplate crea una tabella HTML per visualizzare l'elenco e ItemTemplate specifica le colonne da visualizzare. L'ID studente e il grado degli studenti provengono dall'entità StudentGrade e il nome dello studente proviene dall'entità Person che Entity Framework rende disponibile nella Person proprietà di spostamento dell'entità StudentGrade .

In Instructors.aspx.cs sostituire il metodo sbbed-out CourseDetailsEntityDataSource_Selected con il codice seguente:

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

L'argomento evento per questo evento fornisce i dati selezionati sotto forma di una raccolta, che avrà zero elementi se non viene selezionato alcun elemento o un elemento se è selezionata un'entità Course . Se viene selezionata un'entità Course , il codice usa il First metodo per convertire la raccolta in un singolo oggetto. Ottiene quindi StudentGrade entità dalla proprietà di spostamento, le converte in una raccolta e associa il GradesListView controllo alla raccolta.

Ciò è sufficiente per visualizzare i voti, ma si vuole assicurarsi che il messaggio nel modello di dati vuoto venga visualizzato la prima volta che viene visualizzata la pagina e ogni volta che un corso non è selezionato. A tale scopo, creare il metodo seguente, che verrà chiamato da due posizioni:

private void ClearStudentGradesDataSource()
{
    var emptyStudentGradesList = new List<StudentGrade>();
    GradesListView.DataSource = emptyStudentGradesList;
    GradesListView.DataBind();
}

Chiamare questo nuovo metodo dal Page_Load metodo per visualizzare il modello di dati vuoto la prima volta che viene visualizzata la pagina. E chiamarlo dal InstructorsGridView_SelectedIndexChanged metodo perché tale evento viene generato quando viene selezionato un insegnante, il che significa che i nuovi corsi vengono caricati nel controllo dei corsi GridView e nessuno è ancora selezionato. Ecco le due chiamate:

protected void Page_Load(object sender, EventArgs e)
{
    if (!IsPostBack)
    {
        ClearStudentGradesDataSource();                
    }
}
protected void InstructorsGridView_SelectedIndexChanged(object sender, EventArgs e)
{
    ClearStudentGradesDataSource();
}

Eseguire la pagina.

Immagine08

Selezionare un insegnante che ha un corso assegnato e quindi selezionare il corso.

Immagine09

Sono stati ora illustrati alcuni modi per lavorare con i dati correlati. Nell'esercitazione seguente si apprenderà come aggiungere relazioni tra entità esistenti, come rimuovere relazioni e come aggiungere una nuova entità con una relazione a un'entità esistente.