Entity Framework è l’ORM (Object-Relational Mapping) introdotto dalla Microsoft, che utilizza un insieme di tecnologie ADO.NET che supportano lo sviluppo di applicazioni orientate ai dati, al fine di poter gestire la persistenza e l’elaborazione dei dati, mediante una logica object oriented. Ciò significa che i dati memorizzati in un database vengono esposti al programmatore sotto forma di proprietà e oggetti di uno specifico dominio, (per esempio clienti, prodotti, indirizzo, ecc).
Entity Framework, consente di ridurre la quantità di codice che occorre scrivere. Supporta i tre diversi modi di rappresentare l’ereditarietà sul database (concettuale, mapping e logico), non obbliga a modellare le classi di dominio sulle singole tabelle ed è caratterizzato da una buona logica di gestione della concorrenza.
Per definire i tre modelli, Entity Framework, utilizza un file in formato XML; inoltre genera una serie di classi, basate sul modello concettuale, che possono essere utilizzate per interagire direttamente con i dati. In questo modo si ottiene un'astrazione mediante la quale, è possibile utilizzare un modello concettuale, in sostituzione del modello relazionale.
Entity Framework utilizza come linguaggio di interrogazione Linq to Entities che supporta tutti gli operatori standard di LINQ ad eccezione degli overload che accettano in input l'indice in cui si trova l'elemento. E’ anche possibile eseguire le interrogazioni con un ulteriore linguaggio realizzato sulla base di SQL, simile a Linq to Entities, ma a differenza di questo, le query vengono espresse in formato stringa. Tuttavia per la sua estrema semplicità, Linq to Entities è da preferire a Query Entity SQL. Entity Framework, supporta i tre diversi modi di rappresentare l’ereditarietà sul database, non obbliga a modellare le classi di dominio sulle singole tabelle ed è caratterizzato da una buona logica di gestione della concorrenza. L’architettura di Entity Framework è la seguente:
Oltre ai due linguaggi, Query Entity SQL e Linq to Entities, un ulteriore importante componente è l’Entity Data Model (EDM) che effettua la conversione fra il modello concettuale e quello di archiviazione.
L’Entity Data Model è il componente che effettua il mapping fra le tabelle del database e le classi del dominio applicativo, sulla base di un file di mapping esterno, in formato XML, in cui viene descritto come le classi sono mappate. Questo file viene utilizzato da Entity Framework per trasformare le operazioni sulle entità e relazioni del modello concettuale, in equivalenti operazioni sull’origine dei dati. Questo file, in formato XML, comprende tre diverse sezioni:
-
SSDL (Storage Schema Definition Language), in cui viene definito il modello di archiviazione (o modello logico) il cui fine è di descrivere la struttura del database (tabelle, singoli campi, chiave primarie, relazioni, ecc), le funzioni e le stored procedure.
-
CSDL (Conceptual Schema Definition Language), in cui viene definito il modello concettuale. Il fine è di definire le entità, le relazioni e di descrivere le classi del domino, il tipo di dato che contengono, le relazioni con le altre classi, ecc.
-
MSL (Mapping Specification Language), in cui viene definito il mapping fra il modello di archiviazione e il modello concettuale, cioè il mapping fra le classi e il database.
L’utilizzo di Entity Framework è semplificato da un designer visuale, presente in Visual Studio, in grado di automatizzare quasi tutte le operazioni di mapping. Il designer genera un file con l’estensiore edmx che contiene le tre diverse sezioni.
L’Object Services è un componente, il cui principale compito è quello di fornire l’accesso alla classe ObjectQuery<T>, la cui funzione è di eseguire l’interrogazione e quindi di trasformare i dati dal modello di archiviazione tabellare, nel modello concettuale; inoltre memorizza lo stato degli oggetti, in modo da riportarli nel database, nell’istante in cui l’utente decide di renderli persistenti.
Il Provider Dati Entity Client, gestisce le connessioni e controlla il trasferimento dei dati con il database. In altri termini, interpreta l’expression tree ricavate dalle query LINQ to Entity e Entity SQL ed effettua la query verso il database.
Tradizionalmente, l’interazione fra i sistemi di archiviazione dati e la programmazione object oriented, si realizza eseguendo il mapping delle classi e delle proprietà, alle tabelle e alle colonne della base dei dati. Entity Framework invece, esegue il mapping delle tabelle relazionali, a classi di dati estensibili basate sul modello concettuale; a queste classi, il programmatore può aggiungere ulteriori membri. Le classi generate, derivano da classi base che forniscono Object Services, cioè che effettuano query sui dati, inseriscono, aggiornano ed eliminano i dati, espressi come oggetti fortemente tipizzati. Object Services, oltre a restituire i dati come oggetti, consente anche di propagare le modifiche degli oggetti, nell’origine dei dati. Infine fornisce le funzionalità per rilevare le modifiche e gestire la concorrenza.
La principale classe di Entity Framework, che interagisce con i dati sotto forma di oggetti è l’ObjectContext. Una sua instanza incapsula:
-
la connessione al database sotto forma di oggetto EntityConnection
-
i metadati che descrivono il modello sotto forma di oggetto MetadataWorkspace
-
l’oggetto ObjectStateManager, che tiene traccia degli oggetti durante le operazioni di creazione, aggiornamento ed eliminazione.
Il codice relativo agli oggetti, viene generato utilizzando il file CSDL. Questo codice contiene:
-
la classe ObjectContex tipizzata, che rappresenta l’oggetto EntityContainer, derivata da ObjectContext;
-
le classi derivate da EntityObject, che rappresentano i tipi di entità;
-
le classi derivate da ComplexObject, che rappresentano i tipi complessi.
Dopo aver creato il database e un progetto Visual Studio è possibile generare un Entity Data Model del database, mediante il quale verranno eseguite tutte le operazioni di ADO.NET Entity Framework.
Per creare questo modello, in Esplora soluzioni, posizionarsi sulla cartella Models, selezionare Aggiungi e quindi fare clic su Nuovo elemento. Viene visualizzato il form che segue:
In Modelli installati, selezionare Dati e quindi ADO.NET Entity Data Model, mentre nel campo Nome digitare il nome che si desidera assegnare al Data Model (per esempio MvcIdea.edmx) ed infine fare clic sul pulsante Aggiungi.
Scegliere Genera da database e quindi fare clic sul pulsante Avanti.
Fare clic sul pulsante Nuova connessione, al fine di scegliere il database su cui costruire il Data Model. Viene visualizzato la scheda che segue:
Selezionare il Server (per esempio NOTEBOOK) in cui vi è il database e quindi dal menu a tendina Seleziona o immetti nome di database, il nome del database (per esempio Evolution) ed infine fare clic su OK. Viene visualizzata la scheda precedente con i campi opportunamente compilati. Fare clic sul pulsante Avanti
Scegliere gli oggetti di database da includere nel Data Model e quindi fare clic su pulsante Fine.
Al termine della procedura viene visualizzato l’Entity Diagram del database e vengono aggiunti, in Esplora soluzioni, cartella Models, il file Evolution.edmx che contiene il mapping e il file Evolution.Designer.cs che contiene il codice relativo alle classi generate.
Un fondamentale componente di Entity Framework è Object Services, il cui fine è di eseguire query sui dati come oggetti e di aggiornare, inserire ed eliminare i dati, espressi come oggetti CLR fortemente tipizzati. Supporta query LINQ e query Entity SQL, sui tipi dati definiti nel modello concettuale. Inoltre fornisce le funzionalità per rilevare le modifiche, per gestire la concorrenza e per associare gli oggetti ai controlli. Le principali funzionalità di Object Services sono:
-
Esecuzione di query sul modello concettuale, al fine di restituire i dati come oggetti Determinazione della struttura dei risultati delle query. Infatti, se sono presenti relazioni tra gli oggetti è possibile specificare nella query di restituire anche gli oggetti correlati
-
Aggiunta, modifica ed eliminazione di oggetti, nel contesto dell’oggetto. Ad esempio, quando viene invocato il metodo SaveChanges(), vengono generati e avviati, sull'origine dati, i comandi necessari per eseguire le istruzioni INSERT, UPDATE o DELETE. Per impostazione predefinita, Entity Framework implementa il modello di concorrenza ottimistica.
-
Associazione degli oggetti ai controlli che supportano l’associazione dati (ad esempio, DataGridView, ComboBox, ListView, ecc.)
-
Connessione degli oggetti esistenti, direttamente al contesto dell’oggetto. Quando viene eseguita una query in un contesto dell'oggetto, gli oggetti restituiti vengono automaticamente connessi al contesto dell'oggetto
-
Disconnessione degli oggetti. E’ possibile disconnettere gli oggetti, al fine di risparmiare risorse, in quanto l'esecuzione di query ripetute nello stesso contesto dell'oggetto, determinano l'aumento delle risorse
-
Utilizzazione di Identity. In Object Services vengono utilizzati i valori Identity per rilevare le modifiche agli oggetti, gestire i conflitti e stabilire quando recuperare i dati dall'origine dati.
-
Gestione delle connessioni. Per impostazione predefinita, la connessione al database viene gestita da Entity Framework. Tuttavia è possibile gestire manualmente sia le connessioni che le transazioni. Entity Framework apre connessioni solo quando è necessario, per eseguire ad esempio, una query o chiamare SaveChanges() e chiude la connessione quando l'operazione è stata completa.
-
Gestione delle transazioni, sono supportate in Object Services per coordinare le operazioni nell'origine dati e per l'inserimento nelle transazioni distribuite.
-
Entity Framework consente di utilizzare classi dati personalizzate, insieme al modello dati, senza effettuare modifica alle classi di dati. Infatti è possibile utilizzare oggetti POCO (Plain-Old CLR Object) con il modello dati. Queste classi, note anche come oggetti che non riconoscono la persistenza, mappate a entità definite nel modello di dati, supportano la maggior parte dei comportamenti di query, inserimento, aggiornamento ed eliminazione dei tipi di entità generati dagli strumenti del Modello dati entità.
Gestione della concorrenza
Per impostazione predefinita, Entity Framework implementa un modello di concorrenza ottimistica. Ciò significa che non vengono mantenuti blocchi sui dati, nell'origine dati, tra il momento in cui viene eseguita la query sui dati e il relativo aggiornamento. Se esiste un alto livello di concorrenza, è opportuno definire una proprietà a livello concettuale con l’attributo ConcurrencyMode="fixed", come indicato nell’esempio che segue:
<property name="Status" type="Byte" nullable="false" concurrencymode="Fixed">
</property>
in questi casi Entity Framework, prima di salvare le modifiche nel database, verifica se esiste un conflitto fra i valori. Se esiste un conflitto Entity Framework genera l’evento OptimisticConcurrencyException.
try {
context.SaveChanges();
. . . .
}
catch (OptimisticConcurrencyException) {
// Risolvere il conflitto mediante il refresh dell’object context,
// prima di salvare le variazioni.
context.Refresh(RefreshMode.ClientWins, . . .);
context.SaveChanges();
}