Introduzione con Entity Framework 4.0 Database First e ASP.NET 4 Web Forms - Parte 2
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
Controllo EntityDataSource
Nell'esercitazione precedente è stato creato un sito Web, un database e un modello di dati. In questa esercitazione si usa il EntityDataSource
controllo fornito da ASP.NET per semplificare l'uso di un modello di dati di Entity Framework. Si creerà un GridView
controllo per la visualizzazione e la modifica dei dati degli studenti, un DetailsView
controllo per l'aggiunta di nuovi studenti e un DropDownList
controllo per la selezione di un reparto (che verrà usato più avanti per la visualizzazione dei corsi associati).
Si noti che in questa applicazione non si aggiungerà la convalida di input alle pagine che aggiornano il database e alcune delle operazioni di gestione degli errori non saranno affidabili come sarebbe necessario in un'applicazione di produzione. In questo modo l'esercitazione è incentrata su Entity Framework e la impedisce di ottenere troppo tempo. Per informazioni dettagliate su come aggiungere queste funzionalità all'applicazione, vedere Convalida dell'input dell'utente in Pagine Web ASP.NET e gestione degli errori in ASP.NET pagine e applicazioni.
Aggiunta e configurazione del controllo EntityDataSource
Si inizierà configurando un EntityDataSource
controllo per leggere Person
le entità dal People
set di entità.
Assicurarsi di avere aperto Visual Studio e di usare il progetto creato nella parte 1. Se il progetto non è stato compilato dopo aver creato il modello di dati o dopo l'ultima modifica apportata, compilare ora il progetto. Le modifiche apportate al modello di dati non vengono rese disponibili per la finestra di progettazione fino alla compilazione del progetto.
Creare una nuova pagina Web usando il modello Pagina master usando il modello Pagina master e denominarlo Students.aspx.
Specificare Site.Master come pagina master. Tutte le pagine create per queste esercitazioni useranno questa pagina master.
Nella visualizzazione Origine aggiungere un'intestazione h2
al Content
controllo denominato Content2
, come illustrato nell'esempio seguente:
<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">
<h2>Student List</h2>
</asp:Content>
Dalla scheda Dati della Casella degli strumenti trascinare un EntityDataSource
controllo nella pagina, rilasciarlo sotto l'intestazione e modificare l'ID in StudentsEntityDataSource
:
<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">
<h2>Student List</h2>
<asp:EntityDataSource ID="StudentsEntityDataSource" runat="server">
</asp:EntityDataSource>
</asp:Content>
Passare alla visualizzazione Progettazione , fare clic sullo smart tag del controllo origine dati e quindi su Configura origine dati per avviare la procedura guidata Configura origine dati .
Nel passaggio Configura objectContext della procedura guidata selezionare SchoolEntities come valore per Connessione denominata e selezionare SchoolEntities come valore DefaultContainerName . Quindi fare clic su Avanti.
Nota: se a questo punto viene visualizzata la finestra di dialogo seguente, è necessario compilare il progetto prima di procedere.
Nel passaggio Configura selezione dati selezionare Persone come valore per EntitySetName. In Seleziona verificare che la casella di controllo Seleziona A sia selezionata. Selezionare quindi le opzioni per abilitare l'aggiornamento e l'eliminazione. Al termine, fare clic su Fine.
Configurazione delle regole di database per consentire l'eliminazione
Verrà creata una pagina che consente agli utenti di eliminare gli studenti dalla Person
tabella, che ha tre relazioni con altre tabelle (Course
, StudentGrade
e OfficeAssignment
). Per impostazione predefinita, il database impedisce l'eliminazione di una riga in Person
se sono presenti righe correlate in una delle altre tabelle. È possibile eliminare manualmente prima le righe correlate oppure configurare il database per eliminarle automaticamente quando si elimina una Person
riga. Per i record degli studenti in questa esercitazione, si configurerà il database per eliminare automaticamente i dati correlati. Poiché gli studenti possono avere righe correlate solo nella StudentGrade
tabella, è necessario configurare solo una delle tre relazioni.
Se si usa il file School.mdf scaricato dal progetto che include questa esercitazione, è possibile ignorare questa sezione perché queste modifiche alla configurazione sono già state apportate. Se il database è stato creato eseguendo uno script, configurare il database eseguendo le procedure seguenti.
In Esplora server aprire il diagramma di database creato nella parte 1. Fare clic con il pulsante destro del mouse sulla relazione tra Person
e StudentGrade
(la linea tra le tabelle) e quindi scegliere Proprietà.
Nella finestra Proprietà espandere INSERT e UPDATE Specification e impostare la proprietà DeleteRule su Cascade.
Salvare e chiudere il diagramma. Se viene chiesto se si vuole aggiornare il database, fare clic su Sì.
Per assicurarsi che il modello mantenga le entità in memoria sincronizzate con le operazioni eseguite dal database, è necessario impostare le regole corrispondenti nel modello di dati. Aprire SchoolModel.edmx, fare clic con il pulsante destro del mouse sulla linea di associazione tra Person
e StudentGrade
e quindi scegliere Proprietà.
Nella finestra Proprietà impostare End1 OnDelete su Cascade.
Salvare e chiudere il file SchoolModel.edmx e quindi ricompilare il progetto.
In generale, quando il database cambia, sono disponibili diverse opzioni per la sincronizzazione del modello:
- Per determinati tipi di modifiche, ad esempio l'aggiunta o l'aggiornamento di tabelle, viste o stored procedure, fare clic con il pulsante destro del mouse nella finestra di progettazione e selezionare Aggiorna modello dal database per fare in modo che la finestra di progettazione faccia in modo che le modifiche vengano apportate automaticamente.
- Rigenerare il modello di dati.
- Apportare aggiornamenti manuali come questo.
In questo caso, è possibile rigenerare il modello o aggiornare le tabelle interessate dalla modifica della relazione, ma è necessario apportare nuovamente la modifica del nome del campo (da FirstName
a FirstMidName
).
Uso di un controllo GridView per leggere e aggiornare le entità
In questa sezione si userà un GridView
controllo per visualizzare, aggiornare o eliminare studenti.
Aprire o passare a Students.aspx e passare alla visualizzazione Struttura . Nella scheda Dati della Casella degli strumenti trascinare un GridView
controllo a destra del EntityDataSource
controllo, denominarlo StudentsGridView
, fare clic sullo smart tag e quindi selezionare StudentsEntityDataSource come origine dati.
Fare clic su Aggiorna schema (fare clic su Sì se viene richiesto di confermare), quindi fare clic su Abilita paging, Abilita ordinamento, Abilita modifica e Abilita eliminazione.
Fare clic su Modifica colonne.
Nella casella Campi selezionati eliminare PersonID, LastName e HireDate. In genere non viene visualizzata una chiave di record per gli utenti, la data di assunzione non è rilevante per gli studenti e si inseriscono entrambe le parti del nome in un campo, quindi è necessario solo uno dei campi del nome.
Selezionare il campo FirstMidName e quindi fare clic su Converti questo campo in un campo Modello.
Eseguire la stessa operazione per EnrollmentDate.
Fare clic su OK e quindi passare a Visualizzazione origine . Le modifiche rimanenti saranno più facili da eseguire direttamente nel markup. Il markup del GridView
controllo è ora simile all'esempio seguente.
<asp:GridView ID="StudentsGridView" runat="server" AllowPaging="True"
AllowSorting="True" AutoGenerateColumns="False" DataKeyNames="PersonID"
DataSourceID="StudentsEntityDataSource">
<Columns>
<asp:CommandField ShowDeleteButton="True" ShowEditButton="True" />
<asp:TemplateField HeaderText="FirstMidName" SortExpression="FirstMidName">
<EditItemTemplate>
<asp:TextBox ID="TextBox1" runat="server" Text='<%# Bind("FirstMidName") %>'></asp:TextBox>
</EditItemTemplate>
<ItemTemplate>
<asp:Label ID="Label1" runat="server" Text='<%# Bind("FirstMidName") %>'></asp:Label>
</ItemTemplate>
</asp:TemplateField>
<asp:TemplateField HeaderText="EnrollmentDate" SortExpression="EnrollmentDate">
<EditItemTemplate>
<asp:TextBox ID="TextBox2" runat="server" Text='<%# Bind("EnrollmentDate") %>'></asp:TextBox>
</EditItemTemplate>
<ItemTemplate>
<asp:Label ID="Label2" runat="server" Text='<%# Bind("EnrollmentDate") %>'></asp:Label>
</ItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>
La prima colonna dopo il campo del comando è un campo modello che attualmente visualizza il nome. Modificare il markup per questo campo modello in modo che sia simile all'esempio seguente:
<asp:TemplateField HeaderText="Name" SortExpression="LastName">
<EditItemTemplate>
<asp:TextBox ID="LastNameTextBox" runat="server" Text='<%# Bind("LastName") %>'></asp:TextBox>
<asp:TextBox ID="FirstNameTextBox" runat="server" Text='<%# Bind("FirstMidName") %>'></asp:TextBox>
</EditItemTemplate>
<ItemTemplate>
<asp:Label ID="LastNameLabel" runat="server" Text='<%# Eval("LastName") %>'></asp:Label>,
<asp:Label ID="FirstNameLabel" runat="server" Text='<%# Eval("FirstMidName") %>'></asp:Label>
</ItemTemplate>
</asp:TemplateField>
In modalità di visualizzazione, due Label
controlli visualizzano il nome e il cognome. In modalità di modifica, vengono fornite due caselle di testo in modo da poter modificare il nome e il cognome. Come per i Label
controlli in modalità di visualizzazione, si usano Bind
espressioni ed Eval
esattamente come si farebbe con ASP.NET controlli origine dati che si connettono direttamente ai database. L'unica differenza è che si specificano proprietà di entità anziché colonne di database.
L'ultima colonna è un campo modello che visualizza la data di registrazione. Modificare il markup per questo campo in modo che sia simile all'esempio seguente:
<asp:TemplateField HeaderText="Enrollment Date" SortExpression="EnrollmentDate">
<EditItemTemplate>
<asp:TextBox ID="EnrollmentDateTextBox" runat="server" Text='<%# Bind("EnrollmentDate", "{0:d}") %>'></asp:TextBox>
</EditItemTemplate>
<ItemTemplate>
<asp:Label ID="EnrollmentDateLabel" runat="server" Text='<%# Eval("EnrollmentDate", "{0:d}") %>'></asp:Label>
</ItemTemplate>
</asp:TemplateField>
Sia in modalità di visualizzazione che di modifica, la stringa di formato "{0,d}" determina la visualizzazione della data nel formato "data breve". Il computer potrebbe essere configurato per visualizzare questo formato in modo diverso rispetto alle immagini visualizzate in questa esercitazione.
Si noti che in ognuno di questi campi modello, la finestra di progettazione usa un'espressione Bind
per impostazione predefinita, ma è stata modificata in un'espressione Eval
ItemTemplate
negli elementi . L'espressione Bind
rende i dati disponibili nelle GridView
proprietà del controllo nel caso in cui sia necessario accedere ai dati nel codice. In questa pagina non è necessario accedere a questi dati nel codice, quindi è possibile usare Eval
, che è più efficiente. Per altre informazioni, vedere Recupero dei dati dai controlli dati.
Revisione del markup del controllo EntityDataSource per migliorare le prestazioni
Nel markup per il EntityDataSource
controllo rimuovere gli ConnectionString
attributi e DefaultContainerName
e sostituirli con un ContextTypeName="ContosoUniversity.DAL.SchoolEntities"
attributo . Si tratta di una modifica che è necessario apportare ogni volta che si crea un EntityDataSource
controllo, a meno che non sia necessario usare una connessione diversa da quella hardcoded nella classe di contesto dell'oggetto. L'uso dell'attributo ContextTypeName
offre i vantaggi seguenti:
- Prestazioni migliori. Quando il
EntityDataSource
controllo inizializza il modello di dati usando gliConnectionString
attributi eDefaultContainerName
, esegue operazioni aggiuntive per caricare i metadati in ogni richiesta. Non è necessario se si specifica l'attributoContextTypeName
. - Il caricamento differita è attivato per impostazione predefinita nelle classi di contesto oggetto generate (ad esempio
SchoolEntities
in questa esercitazione) in Entity Framework 4.0. Ciò significa che le proprietà di navigazione vengono caricate automaticamente con i dati correlati quando necessario. Il caricamento differita viene illustrato in modo più dettagliato più avanti in questa esercitazione. - Tutte le personalizzazioni applicate alla classe del contesto dell'oggetto (in questo caso la
SchoolEntities
classe ) saranno disponibili per i controlli che usano ilEntityDataSource
controllo . La personalizzazione della classe di contesto dell'oggetto è un argomento avanzato non trattato in questa serie di esercitazioni. Per altre informazioni, vedere Estensione dei tipi generati da Entity Framework.
Il markup sarà ora simile all'esempio seguente (l'ordine delle proprietà potrebbe essere diverso):
<asp:EntityDataSource ID="StudentsEntityDataSource" runat="server"
ContextTypeName="ContosoUniversity.DAL.SchoolEntities" EnableFlattening="False"
EntitySetName="People"
EnableDelete="True" EnableUpdate="True">
</asp:EntityDataSource>
L'attributo EnableFlattening
fa riferimento a una funzionalità necessaria nelle versioni precedenti di Entity Framework perché le colonne chiave esterna non sono state esposte come proprietà di entità. La versione corrente consente di usare associazioni di chiavi esterne, ovvero le proprietà di chiave esterna vengono esposte per tutte le associazioni molti-a-molti. Se le entità hanno proprietà di chiave esterna e nessun tipo complesso, è possibile lasciare questo attributo impostato su False
. Non rimuovere l'attributo dal markup, perché il valore predefinito è True
. Per altre informazioni, vedere Flattening Objects (EntityDataSource).
Eseguire la pagina e visualizzare un elenco di studenti e dipendenti (si filtra solo per gli studenti nell'esercitazione successiva). Il nome e il cognome vengono visualizzati insieme.
Per ordinare la visualizzazione, fare clic su un nome di colonna.
Fare clic su Modifica in qualsiasi riga. Le caselle di testo vengono visualizzate in cui è possibile modificare il nome e il cognome.
Il pulsante Elimina funziona anche. Fare clic su Elimina per una riga con una data di registrazione e la riga scompare. Le righe senza una data di registrazione rappresentano insegnanti e si potrebbe ottenere un errore di integrità referenziale. Nell'esercitazione successiva si filtra l'elenco in modo da includere solo studenti.
Visualizzazione di dati da una proprietà di navigazione
Si supponga ora di voler conoscere il numero di corsi a cui ogni studente è iscritto. Entity Framework fornisce tali informazioni nella StudentGrades
proprietà di navigazione dell'entità Person
. Poiché la progettazione del database non consente l'iscrizione di uno studente in un corso senza avere un voto assegnato, per questa esercitazione è possibile presupporre che la presenza di una riga nella riga di StudentGrade
tabella associata a un corso sia uguale a quella registrata nel corso. La Courses
proprietà di navigazione è solo per gli istruttori.
Quando si usa l'attributo ContextTypeName
del EntityDataSource
controllo, Entity Framework recupera automaticamente le informazioni per una proprietà di navigazione quando si accede a tale proprietà. Questa operazione è denominata caricamento differita. Tuttavia, ciò può risultare inefficiente, perché comporta una chiamata separata al database ogni volta che sono necessarie informazioni aggiuntive. Se sono necessari dati dalla proprietà di navigazione per ogni entità restituita dal EntityDataSource
controllo, è più efficiente recuperare i dati correlati insieme all'entità stessa in una singola chiamata al database. Viene chiamato caricamento eager e si specifica il caricamento eager per una proprietà di navigazione impostando la Include
proprietà del EntityDataSource
controllo .
In Students.aspx si vuole mostrare il numero di corsi per ogni studente, quindi il caricamento eager è la scelta migliore. Se si visualizzano tutti gli studenti, ma si mostra il numero di corsi solo per alcuni di essi (che richiederebbe la scrittura di codice oltre al markup), il caricamento differita potrebbe essere una scelta migliore.
Aprire o passare a Students.aspx, passare alla visualizzazione Progettazione , selezionare StudentsEntityDataSource
e nella finestra Proprietà impostare la proprietà Includi su StudentGrades. Se si desidera ottenere più proprietà di navigazione, è possibile specificare i nomi separati da virgole, ad esempio StudentGrades, Courses.
Passare alla visualizzazione Origine . StudentsGridView
Nel controllo, dopo l'ultimo asp:TemplateField
elemento, aggiungere il nuovo campo modello seguente:
<asp:TemplateField HeaderText="Number of Courses">
<ItemTemplate>
<asp:Label ID="Label1" runat="server" Text='<%# Eval("StudentGrades.Count") %>'></asp:Label>
</ItemTemplate>
</asp:TemplateField>
Nell'espressione Eval
è possibile fare riferimento alla proprietà StudentGrades
di navigazione . Poiché questa proprietà contiene una raccolta, dispone di una Count
proprietà che è possibile utilizzare per visualizzare il numero di corsi in cui viene registrato lo studente. In un'esercitazione successiva si vedrà come visualizzare i dati dalle proprietà di navigazione che contengono singole entità anziché raccolte. Si noti che non è possibile utilizzare BoundField
elementi per visualizzare i dati dalle proprietà di navigazione.
Eseguire la pagina e ora viene visualizzato il numero di corsi a cui ogni studente è iscritto.
Uso di un controllo DetailsView per inserire entità
Il passaggio successivo consiste nel creare una pagina con un DetailsView
controllo che consente di aggiungere nuovi studenti. Chiudere il browser e quindi creare una nuova pagina Web usando la pagina master Site.Master . Assegnare alla pagina il nome StudentsAdd.aspx e quindi passare alla visualizzazione Origine .
Aggiungere il markup seguente per sostituire il markup esistente per il Content
controllo denominato Content2
:
<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">
<h2>Add New Students</h2>
<asp:EntityDataSource ID="StudentsEntityDataSource" runat="server"
ContextTypeName="ContosoUniversity.DAL.SchoolEntities" EnableFlattening="False"
EnableInsert="True" EntitySetName="People">
</asp:EntityDataSource>
<asp:DetailsView ID="StudentsDetailsView" runat="server"
DataSourceID="StudentsEntityDataSource" AutoGenerateRows="False"
DefaultMode="Insert">
<Fields>
<asp:BoundField DataField="FirstMidName" HeaderText="First Name"
SortExpression="FirstMidName" />
<asp:BoundField DataField="LastName" HeaderText="Last Name"
SortExpression="LastName" />
<asp:BoundField DataField="EnrollmentDate" HeaderText="Enrollment Date"
SortExpression="EnrollmentDate" />
<asp:CommandField ShowInsertButton="True" />
</Fields>
</asp:DetailsView>
</asp:Content>
Questo markup crea un EntityDataSource
controllo simile a quello creato in Students.aspx, ad eccezione del fatto che abilita l'inserimento. Come per il GridView
controllo, i campi associati del DetailsView
controllo vengono codificati esattamente come per un controllo dati che si connette direttamente a un database, ad eccezione del fatto che fanno riferimento alle proprietà dell'entità. In questo caso, il controllo viene usato solo per l'inserimento DetailsView
di righe, quindi è stata impostata la modalità predefinita su Insert
.
Eseguire la pagina e aggiungere un nuovo studente.
Non verrà eseguita alcuna operazione dopo l'inserimento di un nuovo studente, ma se si esegue Students.aspx, verranno visualizzate le nuove informazioni sugli studenti.
Visualizzazione di dati in un elenco di Drop-Down
Nei passaggi seguenti si esegue il databinding di un DropDownList
controllo a un set di entità usando un EntityDataSource
controllo . In questa parte dell'esercitazione non si eseguiranno molte operazioni con questo elenco. Nelle parti successive, tuttavia, si userà l'elenco per consentire agli utenti di selezionare un reparto per visualizzare i corsi associati al reparto.
Creare una nuova pagina Web denominata Courses.aspx. Nella visualizzazione Origine aggiungere un'intestazione al Content
controllo denominato Content2
:
<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">
<h2>Courses by Department</h2>
</asp:Content>
Nella visualizzazione Progettazione aggiungere un EntityDataSource
controllo alla pagina come in precedenza, ad eccezione di questa volta denominarlo DepartmentsEntityDataSource
. Selezionare Reparti come valore EntitySetName e selezionare solo le proprietà DepartmentID e Name .
Dalla scheda Standard della Casella degli strumenti trascinare un DropDownList
controllo nella pagina, denominarlo DepartmentsDropDownList
, fare clic sullo smart tag e selezionare Scegli origine dati per avviare la Configurazione guidata origine dati.
Nel passaggio Scegliere un'origine dati selezionare DepartmentsEntityDataSource come origine dati, fare clic su Aggiorna schema e quindi selezionare Nome come campo dati per visualizzare e DepartmentID come campo dati valore. Fare clic su OK.
Il metodo usato per associare il controllo usando Entity Framework è uguale a quello di altri controlli origine dati ASP.NET ad eccezione delle entità e delle proprietà dell'entità.
Passare alla visualizzazione Origine e aggiungere "Selezionare un reparto:" immediatamente prima del DropDownList
controllo.
Select a department:
<asp:DropDownList ID="DropDownList1" runat="server"
DataSourceID="EntityDataSource1" DataTextField="Name"
DataValueField="DepartmentID">
</asp:DropDownList>
Come promemoria, modificare il markup per il EntityDataSource
controllo in questo momento sostituendo gli ConnectionString
attributi e DefaultContainerName
con un ContextTypeName="ContosoUniversity.DAL.SchoolEntities"
attributo . È spesso consigliabile attendere fino a quando non è stato creato il controllo associato a dati collegato al controllo origine dati prima di modificare il markup del EntityDataSource
controllo, perché dopo aver apportato la modifica, la finestra di progettazione non fornirà un'opzione Aggiorna schema nel controllo associato a dati.
Eseguire la pagina ed è possibile selezionare un reparto dall'elenco a discesa.
In questo modo viene completata l'introduzione all'uso del EntityDataSource
controllo . L'utilizzo di questo controllo in genere non è diverso dall'uso di altri controlli origine dati ASP.NET, ad eccezione del fatto che si fa riferimento a entità e proprietà anziché a tabelle e colonne. L'unica eccezione è quando si vuole accedere alle proprietà di navigazione. Nell'esercitazione successiva si noterà che la sintassi usata con EntityDataSource
il controllo potrebbe anche essere diversa da altri controlli origine dati quando si filtrano, raggruppano e ordinano i dati.