Uso di Entity Framework 4.0 e del controllo ObjectDataSource, parte 1: Introduzione
di Tom Dykstra
Questa serie di esercitazioni si basa sull'applicazione Web Contoso University creata dalla Introduzione con la serie di esercitazioni di Entity Framework 4.0. Se non sono state completate le esercitazioni precedenti, come punto di partenza per questa esercitazione è possibile scaricare l'applicazione creata. È anche possibile scaricare l'applicazione creata dalla serie completa di esercitazioni.
L'applicazione Web di esempio Contoso University illustra come creare applicazioni Web Forms ASP.NET usando Entity Framework 4.0 e Visual Studio 2010. L'applicazione di esempio è un sito Web per un'università contoso fittizia. Include funzionalità, come ad esempio l'ammissione di studenti, la creazione di corsi e le assegnazioni di insegnati.
L'esercitazione mostra esempi in C#. L'esempio scaricabile contiene codice sia in C# che in Visual Basic.
Database First
Esistono tre modi per usare i dati in Entity Framework: Database First, Model First e Code First. Questa esercitazione è per Database First. Per informazioni sulle differenze tra questi flussi di lavoro e indicazioni su come scegliere la soluzione migliore per lo scenario, vedere Flussi di lavoro di sviluppo di Entity Framework.
Web Form
Come la serie di Introduzione, questa serie di esercitazioni usa il modello di Web Forms ASP.NET e presuppone che si sappia usare Web Forms ASP.NET in Visual Studio. In caso contrario, vedere Introduzione con ASP.NET 4,5 Web Forms. Se si preferisce usare il framework MVC ASP.NET, vedere Introduzione con Entity Framework usando ASP.NET MVC.
Versioni software
Illustrato nell'esercitazione Funziona anche con Windows 7 Windows 8 Visual Studio 2010 Visual Studio 2010 Express for Web. L'esercitazione non è stata testata con versioni successive di Visual Studio. Esistono molte differenze tra selezioni di menu, finestre di dialogo e modelli. .NET 4 .NET 4.5 è compatibile con le versioni precedenti con .NET 4, ma l'esercitazione non è stata testata con .NET 4.5. Entity Framework 4 L'esercitazione non è stata testata con versioni successive di Entity Framework. A partire da Entity Framework 5, EF usa per impostazione predefinita l'introdotto DbContext API
con EF 4.1. Il controllo EntityDataSource è stato progettato per usare l'APIObjectContext
. Per informazioni su come usare il controllo EntityDataSource con l'APIDbContext
, vedere questo post di blog.Domande
Se si hanno domande che non sono direttamente correlate all'esercitazione, è possibile pubblicarli nel forum ASP.NET Entity Framework, nel forum entity Framework e LINQ to Entities o StackOverflow.com.
Il EntityDataSource
controllo consente di creare un'applicazione molto rapidamente, ma in genere è necessario mantenere una quantità significativa di logica di business e logica di accesso ai dati nelle pagine con estensione aspx . Se si prevede che l'applicazione cresci in complessità e richieda una manutenzione continua, è possibile investire più tempo di sviluppo in anticipo per creare una struttura di applicazioni a livello n o a livelli più gestibile. Per implementare questa architettura, è possibile separare il livello di presentazione dal livello di logica di business (BLL) e dal livello di accesso ai dati (DAL). Un modo per implementare questa struttura consiste nell'usare il ObjectDataSource
controllo anziché il EntityDataSource
controllo. Quando si usa il controllo, si implementa il ObjectDataSource
codice di accesso ai dati e quindi lo si richiama nelle pagine aspx usando un controllo con molte delle stesse funzionalità di altri controlli dell'origine dati. Ciò consente di combinare i vantaggi di un approccio a livello n con i vantaggi dell'uso di un controllo Web Forms per l'accesso ai dati.
Il ObjectDataSource
controllo offre maggiore flessibilità anche in altri modi. Poiché si scrive il proprio codice di accesso ai dati, è più semplice eseguire più di sola lettura, inserimento, aggiornamento o eliminazione di un tipo di entità specifico, ovvero le attività progettate per il EntityDataSource
controllo. Ad esempio, è possibile eseguire la registrazione ogni volta che un'entità viene aggiornata, archiviare i dati ogni volta che un'entità viene eliminata o aggiornare automaticamente i dati correlati in base alle esigenze quando si inserisce una riga con un valore di chiave esterna.
Logica di business e classi di repository
Un ObjectDataSource
controllo funziona richiamando una classe creata. La classe include metodi che recuperano e aggiornano i dati e forniscono i nomi di tali metodi al ObjectDataSource
controllo nel markup. Durante l'elaborazione di rendering o postback, le ObjectDataSource
chiamate ai metodi specificati.
Oltre alle operazioni CRUD di base, la classe creata da usare con il ObjectDataSource
controllo potrebbe dover eseguire la logica di business quando legge o aggiorna i ObjectDataSource
dati. Ad esempio, quando si aggiorna un reparto, potrebbe essere necessario verificare che nessun altro reparto abbia lo stesso amministratore perché una persona non può essere amministratore di più di un reparto.
In una ObjectDataSource
documentazione, ad esempio la panoramica della classe ObjectDataSource, il controllo chiama una classe denominata oggetto business che include sia la logica di business che la logica di accesso ai dati. In questa esercitazione verranno create classi separate per la logica di business e per la logica di accesso ai dati. La classe che incapsula la logica di accesso ai dati è denominata repository. La classe di logica di business include metodi per la logica di business e metodi di accesso ai dati, ma i metodi di accesso ai dati chiamano il repository per eseguire attività di accesso ai dati.
Si creerà anche un livello di astrazione tra BLL e DAL che facilita l'unit test automatizzato del BLL. Questo livello di astrazione viene implementato creando un'interfaccia e usando l'interfaccia quando si crea un'istanza del repository nella classe business-logic. In questo modo è possibile fornire alla classe business-logic un riferimento a qualsiasi oggetto che implementa l'interfaccia del repository. Per un'operazione normale, viene fornito un oggetto repository che funziona con Entity Framework. Per il test, è possibile fornire un oggetto repository che funziona con i dati archiviati in modo che sia possibile modificare facilmente, ad esempio variabili di classe definite come raccolte.
La figura seguente illustra la differenza tra una classe business-logic che include la logica di accesso ai dati senza un repository e una che usa un repository.
Si inizierà creando pagine Web in cui il ObjectDataSource
controllo è associato direttamente a un repository perché esegue solo attività di accesso ai dati di base. Nell'esercitazione successiva si creerà una classe di logica di business con la logica di convalida e si associa il ObjectDataSource
controllo a tale classe anziché alla classe repository. Si creeranno anche unit test per la logica di convalida. Nella terza esercitazione di questa serie si aggiungeranno funzionalità di ordinamento e filtro all'applicazione.
Le pagine create in questa esercitazione funzionano con il Departments
set di entità del modello di dati creato nella serie di esercitazioni di Introduzione.
Aggiornamento del database e del modello di dati
Questa esercitazione verrà avviata eseguendo due modifiche al database, entrambe le quali richiedono modifiche corrispondenti al modello di dati creato nell'Introduzione con le esercitazioni di Entity Framework e Web Forms. In una di queste esercitazioni sono state apportate modifiche manualmente nella finestra di progettazione per sincronizzare il modello di dati con il database dopo una modifica del database. In questa esercitazione si userà lo strumento Update Model From Database della finestra di progettazione per aggiornare automaticamente il modello di dati.
Aggiunta di una relazione al database
In Visual Studio aprire l'applicazione Web Contoso University creata nell'Introduzione con la serie di esercitazioni Entity Framework e Web Forms e quindi aprire il diagramma del SchoolDiagram
database.
Se si esamina la Department
tabella nel diagramma del database, si noterà che ha una Administrator
colonna. Questa colonna è una chiave esterna alla Person
tabella, ma non viene definita alcuna relazione di chiave esterna nel database. È necessario creare la relazione e aggiornare il modello di dati in modo che Entity Framework possa gestire automaticamente questa relazione.
Nel diagramma di database fare clic con il pulsante destro del mouse sulla Department
tabella e selezionare Relazioni.
Nella casella Relazioni chiave esterna fare clic su Aggiungi, quindi fare clic sui puntini di sospensione per tabelle e specifiche colonne.
Nella finestra di dialogo Tabelle e colonne impostare la tabella e il campo chiave primaria su Person
e PersonID
e e impostare la tabella chiave esterna e il campo su Department
e Administrator
. Quando si esegue questa operazione, il nome della relazione verrà modificato da FK_Department_Department
a FK_Department_Person
.)
Fare clic su OK nella casella Tabelle e colonne , fare clic su Chiudi nella casella Relazioni chiave esterna e salvare le modifiche. Se viene chiesto se si desidera salvare le Person
tabelle e Department
, fare clic su Sì.
Nota
Se sono state eliminate Person
righe che corrispondono ai dati già presenti nella Administrator
colonna, non sarà possibile salvare questa modifica. In tal caso, usare l'editor di tabelle in Esplora server per assicurarsi che il Administrator
valore in ogni Department
riga contenga l'ID di un record effettivamente presente nella Person
tabella.
Dopo aver salvato la modifica, non sarà possibile eliminare una riga dalla Person
tabella se tale persona è un amministratore del reparto. In un'applicazione di produzione viene fornito un messaggio di errore specifico quando un vincolo di database impedisce l'eliminazione o si specifica un'eliminazione a catena. Per un esempio di come specificare un'eliminazione a catena, vedere Entity Framework e ASP.NET – Introduzione Parte 2.
Aggiunta di una visualizzazione al database
Nella nuova pagina Department.aspx che si creerà, si vuole specificare un elenco a discesa degli insegnanti, con nomi in formato "ultimo, primo" in modo che gli utenti possano selezionare amministratori del reparto. Per semplificare questa operazione, si creerà una visualizzazione nel database. La visualizzazione sarà costituita solo dai dati necessari per l'elenco a discesa: il nome completo (formattato correttamente) e la chiave del record.
In Esplora server espandere School.mdf, fare clic con il pulsante destro del mouse sulla cartella Views e scegliere Aggiungi nuova visualizzazione.
Fare clic su Chiudi quando viene visualizzata la finestra di dialogo Aggiungi tabella e incollare l'istruzione SQL seguente nel riquadro SQL:
SELECT LastName + ',' + FirstName AS FullName, PersonID
FROM dbo.Person
WHERE (HireDate IS NOT NULL)
Salvare la vista come vInstructorName
.
Aggiornamento del modello di dati
Nella cartella DAL aprire il file SchoolModel.edmx , fare clic con il pulsante destro del mouse sull'area di progettazione e scegliere Aggiorna modello dal database.
Nella finestra di dialogo Scegli oggetti di database selezionare la scheda Aggiungi e selezionare la visualizzazione appena creata.
Fare clic su Fine.
Nella finestra di progettazione si noterà che lo strumento ha creato un'entità vInstructorName
e una nuova associazione tra le Department
entità e Person
.
Nota
Nelle finestre Output ed Elenco errori potrebbe essere visualizzato un messaggio di avviso che informa che lo strumento ha creato automaticamente una chiave primaria per la nuova vInstructorName
visualizzazione. Si tratta di un comportamento previsto.
Quando si fa riferimento alla nuova vInstructorName
entità nel codice, non si vuole usare la convenzione di database per anteporre un prefisso "v" minuscolo. Di conseguenza, si rinominano l'entità e il set di entità nel modello.
Aprire il Visualizzatore modelli. Viene visualizzato vInstructorName
come tipo di entità e una vista.
In SchoolModel (non SchoolModel.Store) fare clic con il pulsante destro del mouse su vInstructorName e scegliere Proprietà. Nella finestra Proprietà modificare la proprietà Name in "InstructorName" e modificare la proprietà Entity Set Name in "InstructorNames".
Salvare e chiudere il modello di dati e quindi ricompilare il progetto.
Uso di una classe repository e di un controllo ObjectDataSource
Creare un nuovo file di classe nella cartella DAL , denominarlo SchoolRepository.cs e sostituire il codice esistente con il codice seguente:
using System;
using System.Collections.Generic;
using System.Linq;
using ContosoUniversity.DAL;
namespace ContosoUniversity.DAL
{
public class SchoolRepository : IDisposable
{
private SchoolEntities context = new SchoolEntities();
public IEnumerable<Department> GetDepartments()
{
return context.Departments.Include("Person").ToList();
}
private bool disposedValue = false;
protected virtual void Dispose(bool disposing)
{
if (!this.disposedValue)
{
if (disposing)
{
context.Dispose();
}
}
this.disposedValue = true;
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
}
}
Questo codice fornisce un singolo GetDepartments
metodo che restituisce tutte le entità nel Departments
set di entità. Poiché si sa che si accederà alla Person
proprietà di navigazione per ogni riga restituita, è necessario specificare il caricamento eager per tale proprietà usando il Include
metodo . La classe implementa anche l'interfaccia IDisposable
per assicurarsi che la connessione al database venga rilasciata quando l'oggetto viene eliminato.
Nota
Una procedura comune consiste nel creare una classe di repository per ogni tipo di entità. In questa esercitazione viene usata una classe di repository per più tipi di entità. Per altre informazioni sul modello di repository, vedere i post nel blog del team di Entity Framework e nel blog di Julie Lerman.
Il GetDepartments
metodo restituisce un IEnumerable
oggetto anziché un IQueryable
oggetto per garantire che l'insieme restituito sia utilizzabile anche dopo l'eliminazione dell'oggetto repository stesso. Un IQueryable
oggetto può causare l'accesso al database ogni volta che si accede, ma l'oggetto repository potrebbe essere eliminato dal momento in cui un controllo in ingresso tenta di eseguire il rendering dei dati. È possibile restituire un altro tipo di raccolta, ad esempio un IList
oggetto anziché un IEnumerable
oggetto . Tuttavia, la restituzione di un IEnumerable
oggetto garantisce che sia possibile eseguire normali attività di elaborazione degli elenchi di sola lettura, ad foreach
esempio cicli e query LINQ, ma non è possibile aggiungere o rimuovere elementi nella raccolta, il che potrebbe implicare che tali modifiche verrebbero rese persistenti nel database.
Creare una pagina Departments.aspx che usa la pagina master Site.Master e aggiungere il markup seguente nel Content
controllo denominato Content2
:
<h2>Departments</h2>
<asp:ObjectDataSource ID="DepartmentsObjectDataSource" runat="server"
TypeName="ContosoUniversity.DAL.SchoolRepository"
DataObjectTypeName="ContosoUniversity.DAL.Department"
SelectMethod="GetDepartments" >
</asp:ObjectDataSource>
<asp:GridView ID="DepartmentsGridView" runat="server" AutoGenerateColumns="False"
DataSourceID="DepartmentsObjectDataSource" >
<Columns>
<asp:CommandField ShowEditButton="True" ShowDeleteButton="True"
ItemStyle-VerticalAlign="Top">
</asp:CommandField>
<asp:DynamicField DataField="Name" HeaderText="Name" SortExpression="Name" ItemStyle-VerticalAlign="Top" />
<asp:DynamicField DataField="Budget" HeaderText="Budget" SortExpression="Budget" ItemStyle-VerticalAlign="Top" />
<asp:DynamicField DataField="StartDate" HeaderText="Start Date" ItemStyle-VerticalAlign="Top" />
<asp:TemplateField HeaderText="Administrator" SortExpression="Person.LastName" ItemStyle-VerticalAlign="Top" >
<ItemTemplate>
<asp:Label ID="AdministratorLastNameLabel" runat="server" Text='<%# Eval("Person.LastName") %>'></asp:Label>,
<asp:Label ID="AdministratorFirstNameLabel" runat="server" Text='<%# Eval("Person.FirstMidName") %>'></asp:Label>
</ItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>
Questo markup crea un ObjectDataSource
controllo che usa la classe del repository appena creata e un GridView
controllo per visualizzare i dati. Il GridView
controllo specifica i comandi Modifica ed Elimina , ma non è ancora stato aggiunto codice per supportarli.
Diverse colonne usano DynamicField
controlli in modo che sia possibile sfruttare la funzionalità di formattazione e convalida automatica dei dati. Affinché funzionino, sarà necessario chiamare il EnableDynamicData
metodo nel Page_Init
gestore eventi. (DynamicControl
i controlli non vengono usati nel Administrator
campo perché non funzionano con le proprietà di navigazione.
Gli Vertical-Align="Top"
attributi diventeranno importanti in un secondo momento quando si aggiunge una colonna con un controllo annidato GridView
alla griglia.
Aprire il file Departments.aspx.cs e aggiungere l'istruzione seguente using
:
using ContosoUniversity.DAL;
Aggiungere quindi il gestore seguente per l'evento della Init
pagina:
protected void Page_Init(object sender, EventArgs e)
{
DepartmentsGridView.EnableDynamicData(typeof(Department));
}
Nella cartella DAL creare un nuovo file di classe denominato Department.cs e sostituire il codice esistente con il codice seguente:
using System;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
namespace ContosoUniversity.DAL
{
[MetadataType(typeof(DepartmentMetaData))]
public partial class Department
{
}
public class DepartmentMetaData
{
[DataType(DataType.Currency)]
[Range(0, 1000000, ErrorMessage = "Budget must be less than $1,000,000.00")]
public Decimal Budget { get; set; }
[DisplayFormat(DataFormatString="{0:d}",ApplyFormatInEditMode=true)]
public DateTime StartDate { get; set; }
}
}
Questo codice aggiunge metadati al modello di dati. Specifica che la proprietà dell'entità rappresenta effettivamente la Budget
Department
valuta anche se il tipo di dati è Decimal
e specifica che il valore deve essere compreso tra 0 e $1.000.000.00. Specifica inoltre che la StartDate
proprietà deve essere formattata come data nel formato mm/gg/a.
Eseguire la pagina Departments.aspx .
Si noti che, anche se non è stata specificata una stringa di formato nel markup di pagina Departments.aspx per le colonne Budget o Start Date , la formattazione predefinita valuta e data è stata applicata dai DynamicField
controlli utilizzando i metadati forniti nel file Department.cs .
Aggiunta di funzionalità di inserimento ed eliminazione
Aprire SchoolRepository.cs, aggiungere il codice seguente per creare un Insert
metodo e un Delete
metodo. Il codice include anche un metodo denominato GenerateDepartmentID
che calcola il valore successivo della chiave record disponibile da utilizzare dal Insert
metodo . Questa operazione è necessaria perché il database non è configurato per calcolare automaticamente questa impostazione per la Department
tabella.
public void InsertDepartment(Department department)
{
try
{
department.DepartmentID = GenerateDepartmentID();
context.Departments.AddObject(department);
context.SaveChanges();
}
catch (Exception ex)
{
//Include catch blocks for specific exceptions first,
//and handle or log the error as appropriate in each.
//Include a generic catch block like this one last.
throw ex;
}
}
public void DeleteDepartment(Department department)
{
try
{
context.Departments.Attach(department);
context.Departments.DeleteObject(department);
context.SaveChanges();
}
catch (Exception ex)
{
//Include catch blocks for specific exceptions first,
//and handle or log the error as appropriate in each.
//Include a generic catch block like this one last.
throw ex;
}
}
private Int32 GenerateDepartmentID()
{
Int32 maxDepartmentID = 0;
var department = (from d in GetDepartments()
orderby d.DepartmentID descending
select d).FirstOrDefault();
if (department != null)
{
maxDepartmentID = department.DepartmentID + 1;
}
return maxDepartmentID;
}
Metodo Attach
Il DeleteDepartment
metodo chiama il Attach
metodo per ristabilire il collegamento gestito nel gestore dello stato dell'oggetto del contesto dell'oggetto tra l'entità in memoria e la riga del database rappresentata. Questa operazione deve verificarsi prima che il metodo chiami il SaveChanges
metodo .
Il termine contesto dell'oggetto fa riferimento alla classe Entity Framework che deriva dalla ObjectContext
classe usata per accedere ai set di entità e alle entità. Nel codice per questo progetto la classe è denominata SchoolEntities
e un'istanza di è sempre denominata context
. Il gestore dello stato dell'oggetto del contesto dell'oggetto è una classe che deriva dalla ObjectStateManager
classe . Il contatto dell'oggetto utilizza il gestore dello stato dell'oggetto per archiviare gli oggetti entità e tenere traccia del fatto che ognuno sia sincronizzato con la riga o le righe della tabella corrispondenti nel database.
Quando si legge un'entità, il contesto dell'oggetto lo archivia nel gestore dello stato dell'oggetto e tiene traccia del fatto che tale rappresentazione dell'oggetto sia sincronizzata con il database. Ad esempio, se si modifica un valore di proprietà, viene impostato un flag per indicare che la proprietà modificata non è più sincronizzata con il database. Quindi, quando si chiama il SaveChanges
metodo , il contesto dell'oggetto sa cosa fare nel database perché il gestore dello stato dell'oggetto sa esattamente cosa è diverso tra lo stato corrente dell'entità e lo stato del database.
Tuttavia, questo processo in genere non funziona in un'applicazione Web, perché l'istanza del contesto dell'oggetto che legge un'entità, insieme a tutto il relativo gestore dello stato degli oggetti, viene eliminata dopo il rendering di una pagina. L'istanza del contesto dell'oggetto che deve applicare le modifiche è una nuova istanza per l'elaborazione postback. Nel caso del DeleteDepartment
metodo , il ObjectDataSource
controllo ricrea la versione originale dell'entità da valori nello stato di visualizzazione, ma questa entità ricreata Department
non esiste nel gestore dello stato dell'oggetto. Se è stato chiamato il DeleteObject
metodo su questa entità ricreata, la chiamata avrà esito negativo perché il contesto dell'oggetto non sa se l'entità è sincronizzata con il database. Tuttavia, chiamando il Attach
metodo viene ricreato lo stesso rilevamento tra l'entità ricreata e i valori nel database che sono stati originariamente eseguiti automaticamente quando l'entità è stata letta in un'istanza precedente del contesto dell'oggetto.
In alcuni casi il contesto dell'oggetto non deve tenere traccia delle entità nel gestore dello stato dell'oggetto ed è possibile impostare flag per impedirne l'esecuzione. Alcuni esempi sono illustrati nelle esercitazioni successive di questa serie.
Metodo SaveChanges
Questa semplice classe di repository illustra i principi di base di come eseguire operazioni CRUD. In questo esempio il SaveChanges
metodo viene chiamato immediatamente dopo ogni aggiornamento. In un'applicazione di produzione si potrebbe voler chiamare il SaveChanges
metodo da un metodo separato per ottenere un maggiore controllo su quando il database viene aggiornato. Alla fine dell'esercitazione successiva si troverà un collegamento a un white paper che illustra l'unità di lavoro che è un approccio al coordinamento degli aggiornamenti correlati. Si noti anche che nell'esempio il DeleteDepartment
metodo non include codice per la gestione dei conflitti di concorrenza. Il codice a tale scopo verrà aggiunto in un'esercitazione successiva di questa serie.
Recupero dei nomi degli insegnanti da selezionare durante l'inserimento
Gli utenti devono essere in grado di selezionare un amministratore da un elenco a discesa in un elenco a discesa durante la creazione di nuovi reparti. Aggiungere quindi il codice seguente a SchoolRepository.cs per creare un metodo per recuperare l'elenco di insegnanti usando la vista creata in precedenza:
public IEnumerable<InstructorName> GetInstructorNames()
{
return context.InstructorNames.OrderBy("it.FullName").ToList();
}
Creazione di una pagina per l'inserimento di reparti
Creare una pagina DepartmentsAdd.aspx che usa la pagina Site.Master e aggiungere il markup seguente nel Content
controllo denominato Content2
:
<h2>Departments</h2>
<asp:ObjectDataSource ID="DepartmentsObjectDataSource" runat="server"
TypeName="ContosoUniversity.DAL.SchoolRepository" DataObjectTypeName="ContosoUniversity.DAL.Department"
InsertMethod="InsertDepartment" >
</asp:ObjectDataSource>
<asp:DetailsView ID="DepartmentsDetailsView" runat="server"
DataSourceID="DepartmentsObjectDataSource" AutoGenerateRows="False"
DefaultMode="Insert" OnItemInserting="DepartmentsDetailsView_ItemInserting">
<Fields>
<asp:DynamicField DataField="Name" HeaderText="Name" />
<asp:DynamicField DataField="Budget" HeaderText="Budget" />
<asp:DynamicField DataField="StartDate" HeaderText="Start Date" />
<asp:TemplateField HeaderText="Administrator">
<InsertItemTemplate>
<asp:ObjectDataSource ID="InstructorsObjectDataSource" runat="server"
TypeName="ContosoUniversity.DAL.SchoolRepository"
DataObjectTypeName="ContosoUniversity.DAL.InstructorName"
SelectMethod="GetInstructorNames" >
</asp:ObjectDataSource>
<asp:DropDownList ID="InstructorsDropDownList" runat="server"
DataSourceID="InstructorsObjectDataSource"
DataTextField="FullName" DataValueField="PersonID" OnInit="DepartmentsDropDownList_Init">
</asp:DropDownList>
</InsertItemTemplate>
</asp:TemplateField>
<asp:CommandField ShowInsertButton="True" />
</Fields>
</asp:DetailsView>
<asp:ValidationSummary ID="DepartmentsValidationSummary" runat="server"
ShowSummary="true" DisplayMode="BulletList" />
Questo markup crea due ObjectDataSource
controlli, uno per l'inserimento di nuove Department
entità e uno per il recupero dei nomi degli insegnanti per il DropDownList
controllo usato per la selezione degli amministratori del reparto. Il markup crea un DetailsView
controllo per l'immissione di nuovi reparti e specifica un gestore per l'evento del ItemInserting
controllo in modo da poter impostare il valore della Administrator
chiave esterna. Alla fine è un ValidationSummary
controllo per visualizzare i messaggi di errore.
Aprire DepartmentsAdd.aspx.cs e aggiungere l'istruzione seguente using
:
using ContosoUniversity.DAL;
Aggiungere la variabile di classe e i metodi seguenti:
private DropDownList administratorsDropDownList;
protected void Page_Init(object sender, EventArgs e)
{
DepartmentsDetailsView.EnableDynamicData(typeof(Department));
}
protected void DepartmentsDropDownList_Init(object sender, EventArgs e)
{
administratorsDropDownList = sender as DropDownList;
}
protected void DepartmentsDetailsView_ItemInserting(object sender, DetailsViewInsertEventArgs e)
{
e.Values["Administrator"] = administratorsDropDownList.SelectedValue;
}
Il Page_Init
metodo abilita la funzionalità Dynamic Data. Il gestore dell'evento DropDownList
del Init
controllo salva un riferimento al controllo e il gestore per l'evento DetailsView
del Inserting
controllo usa tale riferimento per ottenere il PersonID
valore dell'insegnante selezionato e aggiornare la Administrator
proprietà di chiave esterna dell'entità Department
.
Eseguire la pagina, aggiungere informazioni per un nuovo reparto e quindi fare clic sul collegamento Inserisci .
Immettere i valori per un altro nuovo reparto. Immettere un numero maggiore di 1.000.000.00 nel campo Budget e nella scheda al campo successivo. Nel campo viene visualizzato un asterisco e, se si tiene premuto il puntatore del mouse, è possibile visualizzare il messaggio di errore immesso nei metadati per tale campo.
Fare clic su Inserisci e viene visualizzato il messaggio di errore visualizzato dal ValidationSummary
controllo nella parte inferiore della pagina.
Chiudere quindi il browser e aprire la pagina Departments.aspx . Aggiungere funzionalità di eliminazione alla pagina Departments.aspx aggiungendo un DeleteMethod
attributo al ObjectDataSource
controllo e un DataKeyNames
attributo al GridView
controllo. I tag di apertura per questi controlli saranno ora simili all'esempio seguente:
<asp:ObjectDataSource ID="DepartmentsObjectDataSource" runat="server"
TypeName="ContosoUniversity.DAL.SchoolRepository"
DataObjectTypeName="ContosoUniversity.DAL.Department"
SelectMethod="GetDepartments"
DeleteMethod="DeleteDepartment" >
<asp:GridView ID="DepartmentsGridView" runat="server" AutoGenerateColumns="False"
DataSourceID="DepartmentsObjectDataSource" DataKeyNames="DepartmentID" >
Eseguire la pagina.
Eliminare il reparto aggiunto durante l'esecuzione della pagina DepartmentAdd.aspx .
Aggiunta di funzionalità di aggiornamento
Aprire SchoolRepository.cs e aggiungere il metodo seguente Update
:
public void UpdateDepartment(Department department, Department origDepartment)
{
try
{
context.Departments.Attach(origDepartment);
context.ApplyCurrentValues("Departments", department);
context.SaveChanges();
}
catch (Exception ex)
{
//Include catch blocks for specific exceptions first,
//and handle or log the error as appropriate in each.
//Include a generic catch block like this one last.
throw ex;
}
}
Quando si fa clic su Aggiorna nella pagina Departments.aspx , il ObjectDataSource
controllo crea due Department
entità da passare al UpdateDepartment
metodo. Uno contiene i valori originali archiviati nello stato di visualizzazione e l'altro contiene i nuovi valori immessi nel GridView
controllo. Il codice nel UpdateDepartment
metodo passa l'entità Department
con i valori originali al Attach
metodo per stabilire il rilevamento tra l'entità e ciò che si trova nel database. Il codice passa quindi l'entità Department
con i nuovi valori al ApplyCurrentValues
metodo. Il contesto dell'oggetto confronta i valori precedenti e nuovi. Se un nuovo valore è diverso da un valore precedente, il contesto dell'oggetto modifica il valore della proprietà. Il SaveChanges
metodo aggiorna quindi solo le colonne modificate nel database. Tuttavia, se la funzione di aggiornamento per questa entità è stata mappata a una stored procedure, l'intera riga verrà aggiornata indipendentemente dalle colonne modificate.
Aprire il file Departments.aspx e aggiungere gli attributi seguenti al DepartmentsObjectDataSource
controllo:
UpdateMethod="UpdateDepartment"
ConflictDetection="CompareAllValues"
In questo modo, i valori precedenti devono essere archiviati nello stato di visualizzazione in modo che possano essere confrontati con i nuovi valori nelUpdate
metodo.OldValuesParameterFormatString="orig{0}"
In questo modo viene informato il controllo che il nome del parametro dei valori originali èorigDepartment
.
Il markup per il tag di apertura del ObjectDataSource
controllo ora è simile all'esempio seguente:
<asp:ObjectDataSource ID="DepartmentsObjectDataSource" runat="server"
TypeName="ContosoUniversity.DAL.SchoolRepository"
DataObjectTypeName="ContosoUniversity.DAL.Department"
SelectMethod="GetDepartments" DeleteMethod="DeleteDepartment"
UpdateMethod="UpdateDepartment"
ConflictDetection="CompareAllValues"
OldValuesParameterFormatString="orig{0}" >
Aggiungere un OnRowUpdating="DepartmentsGridView_RowUpdating"
attributo al GridView
controllo. Verrà usato per impostare il valore della Administrator
proprietà in base alla riga selezionata dall'utente in un elenco a discesa. Il tag di apertura ora è simile all'esempio GridView
seguente:
<asp:GridView ID="DepartmentsGridView" runat="server" AutoGenerateColumns="False"
DataSourceID="DepartmentsObjectDataSource" DataKeyNames="DepartmentID"
OnRowUpdating="DepartmentsGridView_RowUpdating">
Aggiungere un EditItemTemplate
controllo per la Administrator
colonna al GridView
controllo, immediatamente dopo il ItemTemplate
controllo per tale colonna:
<EditItemTemplate>
<asp:ObjectDataSource ID="InstructorsObjectDataSource" runat="server" DataObjectTypeName="ContosoUniversity.DAL.InstructorName"
SelectMethod="GetInstructorNames" TypeName="ContosoUniversity.DAL.SchoolRepository">
</asp:ObjectDataSource>
<asp:DropDownList ID="InstructorsDropDownList" runat="server" DataSourceID="InstructorsObjectDataSource"
SelectedValue='<%# Eval("Administrator") %>'
DataTextField="FullName" DataValueField="PersonID" OnInit="DepartmentsDropDownList_Init" >
</asp:DropDownList>
</EditItemTemplate>
Questo EditItemTemplate
controllo è simile al InsertItemTemplate
controllo nella pagina RepartiAggiungi.aspx . La differenza è che il valore iniziale del controllo viene impostato usando l'attributo SelectedValue
.
Prima del GridView
controllo, aggiungere un ValidationSummary
controllo come si è fatto nella pagina RepartiAggiungi.aspx .
<asp:ValidationSummary ID="DepartmentsValidationSummary" runat="server"
ShowSummary="true" DisplayMode="BulletList" />
Aprire Departments.aspx.cs e immediatamente dopo la dichiarazione di classe parziale, aggiungere il codice seguente per creare un campo privato per fare riferimento al DropDownList
controllo:
private DropDownList administratorsDropDownList;
Aggiungere quindi gestori per l'evento DropDownList
del controllo e l'evento GridView
del Init
RowUpdating
controllo:
protected void DepartmentsDropDownList_Init(object sender, EventArgs e)
{
administratorsDropDownList = sender as DropDownList;
}
protected void DepartmentsGridView_RowUpdating(object sender, GridViewUpdateEventArgs e)
{
e.NewValues["Administrator"] = administratorsDropDownList.SelectedValue;
}
Il gestore per l'evento Init
DropDownList
salva un riferimento al controllo nel campo della classe. Il gestore per l'evento RowUpdating
usa il riferimento per ottenere il valore immesso dall'utente e applicarlo alla Administrator
proprietà dell'entità Department
.
Utilizzare la pagina DepartmentAdd.aspx per aggiungere un nuovo reparto, quindi eseguire la pagina Department.aspx e fare clic su Modifica nella riga aggiunta.
Nota
Non sarà possibile modificare le righe non aggiunte, ovvero già presenti nel database, a causa di dati non validi nel database; gli amministratori per le righe create con il database sono studenti. Se si tenta di modificarli, verrà visualizzata una pagina di errore che segnala un errore come 'InstructorsDropDownList' has a SelectedValue which is invalid because it does not exist in the list of items.
Se si immette un importo budget non valido e quindi si fa clic su Aggiorna, viene visualizzato lo stesso asterisco e messaggio di errore visualizzato nella pagina Reparti.aspx .
Modificare un valore di campo o selezionare un amministratore diverso e fare clic su Aggiorna. Viene visualizzata la modifica.
Questa operazione completa l'introduzione all'uso del ObjectDataSource
controllo per operazioni CRUD di base (creare, leggere, aggiornare, eliminare) con Entity Framework. È stata creata un'applicazione semplice a livello n, ma il livello di logica aziendale è ancora strettamente associato al livello di accesso ai dati, che complica gli unit test automatizzati. Nell'esercitazione seguente verrà illustrato come implementare il modello di repository per facilitare l'unit test.