• Share
  • Email
  • Embed
  • Like
  • Save
  • Private Content
Corso .NET - Lezione ADO.NET
 

Corso .NET - Lezione ADO.NET

on

  • 3,853 views

Una breve introduzione ad ADO.NET in C#

Una breve introduzione ad ADO.NET in C#

Statistics

Views

Total Views
3,853
Views on SlideShare
3,743
Embed Views
110

Actions

Likes
2
Downloads
0
Comments
0

4 Embeds 110

http://caspaolo.blogspot.it 61
http://caspaolo.blogspot.com 44
http://www.mybestcv.co.il 4
http://caspaolo.blogspot.com.au 1

Accessibility

Categories

Upload Details

Uploaded via as Microsoft PowerPoint

Usage Rights

© All Rights Reserved

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Processing…
Post Comment
Edit your comment

    Corso .NET - Lezione ADO.NET Corso .NET - Lezione ADO.NET Presentation Transcript

    • + Introduzione a .NET Accesso ai dati Dr. Paolo Casoto, Ph.D. - Copyright 2011
    • + 2 Sommario Cosa vediamo nel corso di questa lezione:  Introduzione a .NET ed all‟ambiente di lavoro Visual Studio.  Introduzione alla tematica dell‟accesso a basi dati mediante utilizzo della tecnologia ADO.NET in modalità connessa e non connessa. Dr. Paolo Casoto, Ph.D. - Copyright 2011
    • + 3 ADO.NET  .NET mette a disposizione degli sviluppatori una specifica serie di classi per l‟accesso a basi di dati locali o remote  ADO.NET: Active Data Object  Lontano parente di ADO, del quale riprende solo il nome e qualche concetto  Mentre ADO è pensato per un approccio di tipo client – server fortemente accoppiato, ADO.NET consente di operare sui dati anche se il client è disconnesso dalla base dati  Il programma dell‟utente (e.g.: desktop, servizio, pagina web ASP, web service) può manipolare i dati localmente ed effettuare in seguito il merging con la base dati. Dr. Paolo Casoto, Ph.D. - Copyright 2011
    • + 4 ADO.NET  ADO.NET è una libreria di tipo managed, che fa uso del medesimo sistema dei tipi di .NET  Dal punto di vista operativo si tratta di un assembly System.Data.dll che presenta al suo interno le classi necessarie all‟interazione con i dati, siano essi SQL oppure no.  ADO.NET si basa su una gerarchia di classi indipendenti dallo specifico DB utilizzato.  Implementando le classi base del namespace è possibile definire uno strumento per l‟accesso ad ogni tipologia di base di dati. Dr. Paolo Casoto, Ph.D. - Copyright 2011
    • + 5 ADO.NET  L‟astrazione introdotta dal pattern Abstract Factory consente al programmatore di operare in maniera del tutto trasparente rispetto alla specifica base di dati utilizzata.  Posso scrivere la mia applicazione operando su un db Access e poi installarla in produzione su un sistema Oracle  Il tutto a patto di utilizzare, all‟interno delle query, una sintassi SQL agnostica rispetto al dialetto dello specifico DB utilizzato  E.g.: se utilizzo su MySQL una query del tipo SELECT * from TABELLA WHERE id>5 LIMIT 5 OFFSET 10 non posso fare affidamento su ADO.NET per rendere la query compatibile con SQL Server, che non garantisce il supporto alla direttiva LIMIT. Dr. Paolo Casoto, Ph.D. - Copyright 2011
    • + 6 ADO.NET  .NET include al suo interno il supporto per 3 diverse tipologie di database, che implementano le rispettive classi astratte ADO.NET:  SQL Server: classi managed ottimizzate per garantire i migliori risultati in termini di performance dal database.  OLE DB: classi per l‟interazione con tutte le sorgenti dati che fanno uso di un protocollo OLE DB, in ambiente Windows.  ODBC: classi per l‟interazione con tutti i database che fanno uso del protocollo Open Database Connectivity  In termini di prestazioni, è consigliato utilizzare SQL Server o, ove non possibile, OLE DB e, solo come ultima possibilità, la connessione ODBC. Dr. Paolo Casoto, Ph.D. - Copyright 2011
    • + 7 Modalità di accesso ai dati  ADO.NET consente tre differenti modalità di accesso ai dati:  Modalità connessa: modalità classica di interazione al database, basata sull‟apertura di una connessione, l‟invio di una o più query e la chiusura della connessione stessa.  Modalità disconnessa: consente di manipolare in insieme di dati (DataSet) in modalità offline, quale copia locale della base di dati. Chi invoca i dati li può utilizzare senza alcun transito di informazioni sulla rete; l‟infrastruttura si occupa di aprire e chiudere opportunamente le connessioni necessarie quando opportuno e di sincronizzare i dati locali con la copia remota presente nella base dati.  Entity Framework: astrazione dai dettagli di basso livelli caratterizzanti l‟interazione con la base di dati SQL. Dr. Paolo Casoto, Ph.D. - Copyright 2011
    • + 8 Classi e strutture dati di ADO.NET  Indipendentemente dallo specifico data provider utilizzato per lo sviluppo della propria soluzione, le seguenti classi sono comuni a tutte le implementazioni dipendenti dal DB adottato:  Connection: consente la connessione ad una sorgente di dati e la gestione delle transazioni, ove supportate dalle base di dati.  DbCommand: rappresenta una query SQL o il riferimento ad una stored procedure presente all‟interno della base dati. Dr. Paolo Casoto, Ph.D. - Copyright 2011
    • + 9 Classi e strutture dati di ADO.NET  DbDataReader: risultato dell‟esecuzione di un DbCommand, rappresenta un cursore sequenziale lato server per l‟accesso ai risultati del comando. Un DbDataReader può essere percorso in una unica direzione.  DbDataAdapter: gestisce il trasferimento di uno specifico DataSet dal server al chiamante. Contiene quattro comandi dedicati alla selezione, inserimento, modifica ed eliminazione delle righe che costituiscono il DataSet.  DbParameter: rappresenta un parametro all‟interno di una query parametrica.  DbTransaction: incapsula una transazione. Dr. Paolo Casoto, Ph.D. - Copyright 2011
    • + 10 Classi e strutture dati di ADO.NET  Le classi esposte dai singoli data provider estendono le classi descritte.  E.g.: , OracleConnection, OdbcConnection, MySqlConnection, et. al.  Una volta appreso il funzionamento delle classi descritte, è semplice adattarle ad altri data provider in modo del tutto trasparente.  Tutte le classi descritte appartengono al namespace System.Data ed al namespace System.Data.Common.  I data provider forniti dal sistema sono inclusi nei namespace System.Data.SqlClient, System.Data.OleDb, System.Data.Odb c. Dr. Paolo Casoto, Ph.D. - Copyright 2011
    • + 11 ADO.NET: struttura Dr. Paolo Casoto, Ph.D. - Copyright 2011
    • + 12 Data provider in ADO.NET  Per accedere a file ACCESS non è previsto uno specifico data provider all‟interno di .NET.  Utilizzare i data provider OLE DB o ODBC per interagire direttamente con l‟engine JET.  Il data provider OLE DB consente l‟accesso a tutte le basi dati compatibili con il classico standard OLE DB basato su COM.  La stringa di connessione definisce quale provider OLE DB deve essere utilizzato per l‟accesso ai dati.  A causa del codice non gestito e della presenza di componenti COM le prestazioni sono limitati; l‟utilizzo del data provider OLE DB deve essere considerato solo in assenza di alternative native o per l‟accesso a SQL Server con versioni precedenti alla 7.0, coni quali il data provider SQL non è compatibile. Dr. Paolo Casoto, Ph.D. - Copyright 2011
    • + 13 Data provider in ADO.NET  Il data provider di SQL Server consente di accedere direttamente al DBMS (dalla versione 7.0) in maniera ottimizzata.  Consente al programmatore di utilizzare alcune particolari funzionalità messe a disposizione da SQL Server.  Il provider SQL Client CE consente l‟accesso al database SQL Server Mobile edition, utilizzati frequentemente in ambito mobile o nel caso di sistemi embedded.  Il provider ODBC consente l‟accesso ad un ampio insieme di DBMS, al costo di minori prestazioni e funzionalità. Dr. Paolo Casoto, Ph.D. - Copyright 2011
    • + 14 Esempio: Passo 1  Creiamo un nuovo progetto Visual Studio di tipo “Console Application”  All‟interno del file principale, caratterizzato dal metodo Main, invochiamo l‟utilizzo delle librerie ADO.NET  Per farlo utilizziamo la parola riservata using indicando i namespace che andremo ad utilizzare, nello specifico using System.Data; using System.Data.OleDb;  La parola riservata using va utilizzata priva della definizione della classe Dr. Paolo Casoto, Ph.D. - Copyright 2011
    • + 15 Esempio: Passo 2  All‟interno del metodo Main creiamo un nuovo oggetto di tipo OleDbConnection. OleDbConnection connection = new OleDbConnection ();  La classe è finalizzata a mappare l‟oggetto di tipo connessione, che rappresenta un connessione reale con il DBMS.  Aggiungiamo ora alla connessione le informazioni relative al DBMS cui connettersi e procediamo all‟apertura della connessione.  Tutto fra try-catch per evitare eventuali eccezioni (e.g.: non ho connettività a disposizione, il DBMS non è raggiungibile, et al.) Dr. Paolo Casoto, Ph.D. - Copyright 2011
    • + 16 Esempio: Passo 3  Come costruiamo la stringa di connessione da fornire all‟oggetto di tipo Connection al fine di attivare la connessione ?  Opzione 1: faccio riferimento al sito http://www.connectionstrings.com  Opzione 2: utilizzo una specifica classe dipendente dal data provider utilizzato, OleDbConnectionStringBuilder, avente come obiettivo la generazione della stringa di connessione  Quali informazioni costituiscono la stringa?  Dipende dal data provider, in generale URL, login e password, tipologia di meccanismo di verifica delle credenziali, et al. Dr. Paolo Casoto, Ph.D. - Copyright 2011
    • + 17 Esempio: Passo 3 Utilizzo Jet come provider OLEDB Nome del file ACCESS Dr. Paolo Casoto, Ph.D. - Copyright 2011
    • + 18 Esempio: Passo 4  Ed attivo la connessione mediante il metodo Open dell‟oggetto OleDbConnection  Se la connessione non va a buon fine, una eccezione è generata e visualizzata nella console dell‟applicativo.  A questo punto aggiungiamo una query, ad esempio finalizzata ad estrarre tutti i record con attributo nome = „Paolo‟ da una tabella Utenti presente all‟interno della base dati ACCESS.  SELECT * FROM Utenti WHERE Nome LIKE „PAOLO‟  A tal fine dobbiamo creare un opportuno comando di interrogazione, rappresentato da una istanza di OleDbCommand Dr. Paolo Casoto, Ph.D. - Copyright 2011
    • + 19 Esempio: Passo 4 A che connessione invio il comando Il testo del mio comando SQLCommandType.Text = QUERYCommandType.StoredProcedure = STORED PROCEDURECommandType.DirectTable = TABELLA nella sua interezza Dr. Paolo Casoto, Ph.D. - Copyright 2011
    • + 20 Esempio: Passo 5  Eseguiamo il comando rispetto alla connessione e verifichiamo i risultati ottenuti presenti all‟interno del DataReader restituito dal metodo ExecuteReader del comando.  Nello specifico un OleDbDataReader  Iteriamo all‟interno dei dati presenti all‟interno di un DataReader mediante un ciclo WHILE  Il metodo Read del DataReader mi consente di sapere se vi siano altre righe da leggere all‟interno dell‟insieme dei dati restituiti.  E‟ possibile ottenere il valore di un attributo di una riga di risultati utilizzando il selettore GetXXX(posizione), dove XXX indica il tipo del dato. Dr. Paolo Casoto, Ph.D. - Copyright 2011
    • + 21 Esempio: Passo 5  Ad esempio:  GetInt32(1) mi restituisce un valore intero presente nella seconda colonna della riga attuale puntata dal cursore di lettura dei dati.  GetString(4) mi restituisce una stringa presente nella quinta colonna della riga attuale puntata dal cursore di lettura dei dati.  GetDateTime(7) mi restituisce una data (con tempo) presente nella ottava colonna della riga attuale puntata dal cursore di lettura dei dati.  Fino alla sua chiusura il DataReader mantiene un lock sulle righe in esso contenute  Attenzione alle prestazioni in situazioni multi-utente  Questo problema è ridotto quando si fa uso del SqlDataReader. Dr. Paolo Casoto, Ph.D. - Copyright 2011
    • + 22 Eseguo il comando Scorro il contenuto del DataReader Rilascio il DataReader Fino qui su tutte le Ed infine la righe vi è un lock connessione Dr. Paolo Casoto, Ph.D. - Copyright 2011
    • + 23 Esempio: Passo 6  E se volessimo inserire all‟interno della nostra query un valore parametrico ? 1. Utilizzo una stringa con il valore parametrico nella costruzione della query SQL  ERRORE GRAVISSIMO !!! Mai fare questo tipo di attività perché sensibili al SQL Injection.  E.g.: e se la stringa fosse ‘’; DROP DB; ??? 2. Utilizzando le istanze della classe OleDbParameter, che consentono di mappare i parametri delle query parametriche.  Nella query SQL sostituisco le incognite con il simbolo @ ed il nome del parametro.  Il sistema automaticamente provvede a costruire la query, formattando opportunamente i valori. Dr. Paolo Casoto, Ph.D. - Copyright 2011
    • + 24 Modifichiamo la query Inserisco il parametro Dr. Paolo Casoto, Ph.D. - Copyright 2011
    • + 25 Alcune considerazioni  La connessione deve essere sempre chiusa, la soluzione ottimale per la chiusura della connessione è all‟interno di un blocco finally.  Non mantenere riferimenti ad un DataReader: potrebbe bloccare altri utenti della base di dati o successive interazioni dello stesso utente mediante una connessione differente.  Sia in definizione della query parametrica, sia in fase di lettura dei dati, tutte le colonne partono con il numero 0.  I parametri delle query parametriche possono avere uno specifico tipo dipendente dal data provider adottato. Dr. Paolo Casoto, Ph.D. - Copyright 2011
    • + 26 Alcune considerazioni  In generale .NET mantiene, per ciascun data provider, un pool di connessioni alla base di dati.  Quando una applicazione richiede di aprire una connessione o ne chiude una esistente, il sistema di pooling in realtà si limita ad allocare o deallocare e rendere nuovamente disponibile una risorsa.  Questo al fine di ridurre le problematiche di alcuni DBMS con numero limitato di connessioni (e.g.: per motivi di licenza).  Mediante la funzione isDBNull(posizione) è possibile accedere anche a valori NULL presenti all‟interno di una colonna del DataReader. Dr. Paolo Casoto, Ph.D. - Copyright 2011
    • + 27 Gestione della stringa di connessione  Come gestire all‟interno di una applicazione con accesso alla base dati da molteplici punti l‟utilizzo della medesima stringa di connessione ?  HARD CODED: e se le devo modificare devo andare a propagare la modifica ovunque e ricompilare ?  In una costante di una classe ? Si ma anche qui, sebbene non mi debba preoccupare di propagare la modifica, devo sempre ricompilare. E poi questa soluzione non va bene se ho più di una base dati cui voglio avere la possibilità di connettermi.  Utilizzando il file di configurazione reso disponibile dalla piattaforma a partire dalla versione 2.0 del framework .NET Dr. Paolo Casoto, Ph.D. - Copyright 2011
    • + 28 Definiamo il file di configurazione Namespace del data Nel nostro caso OLE provider associato al DB DBMS ConnectionString Dr. Paolo Casoto, Ph.D. - Copyright 2011
    • + 29 Utilizziamo il file di configurazione Non conoscendo a priori il tipo del data provider tutti gli oggetti devono essere creati da un oggetto factory Tutti gli oggetti sono ora agnostici rispetto al data provider Dr. Paolo Casoto, Ph.D. - Copyright 2011
    • + 30 Alcune considerazioni  Per utilizzare il file di configurazione devo aggiungere al mio progetto la dll di .NET System.configuration ed il namespace System.Configuration.  Nel file di configurazione posso definire tutte le basi di dati per le quali intendo fornire una stringa di connessione.  E‟ importante definire correttamente il namespace del data provider da utilizzare per la specifica connessione.  Il metodo statico DbProviderFactories.GetFactory mi restituisce un oggetto, propriamente detta factory, in grado di istanziare tutti gli oggetti di un dato data provider. Dr. Paolo Casoto, Ph.D. - Copyright 2011
    • + 31 Alcune considerazioni  Naturalmente a livello di codice sono costretto ad operare in modo del tutto agnostico rispetto allo specifico data provider.  Tutto quello che nel primo programma era di tipo OleDb* ora è diventato del tipo generico Db*  Per poter utilizzare gli oggetti generici di ADO.NET devo provvedere all‟importazione del namespace System.Data.Common.  Quando ha senso questa soluzione?  Quando il db può cambiare nella tipologia al variare del tempo  E.g.: in sviluppo lavoro su ACCESS, in fase di deployment lavoro su SQL Server. Dr. Paolo Casoto, Ph.D. - Copyright 2011
    • + 32 Alcune considerazioni  In generale non ho alcuna perdita in termini prestazionali  Il sistema continuerà ad utilizzare, ad esempio nel caso di SQL Server, il data provider opportuno, ottimizzato.  Ho una potenziale perdita di funzionalità nel caso di specifici comportamenti offerti da un DBMS e dal corrispettivo data provider ma non comuni a tutte le piattaforme.  E.g.: metodi ottimizzati non supportati dalle classi astratte comuni a tutta la gerarchia degli oggetti di ADO.NET  E.g.: metodi propri del DBMS SQL Server. Dr. Paolo Casoto, Ph.D. - Copyright 2011
    • + 33 Chiusura delle connessioni e gestione della memoria  Quando il codice del proprio applicativo effettua la chiusura di una connessione, tutti gli oggetti utilizzati per la specifica collezione sono soggetti al processo di deallocazione mediante garbage collector.  Tuttavia come in tutti i linguaggi moderni non siamo in grado di prevedere quando il garbage collector rimuoverà un oggetto da una locazione di memoria.  Per accertarsi della chiusura e deallocazione di una connessione è possibile utilizzare un costrutto alternativo, il blocco  .NET dealloca forzatamente tutto ciò che è stato definito all‟interno di un blocco  La deallocazione di un oggetto Connection (metodo Dispose) prevede l‟invocazione del metodo Close Dr. Paolo Casoto, Ph.D. - Copyright 2011
    • + 34 All‟uscita dal blocco, per qualsiasi motivo, l‟oggetto connection è deallocato forzatamente Ovvero ne viene invocato il metodo Dispose, la cui prima istruzione è proprio this.Close() Dr. Paolo Casoto, Ph.D. - Copyright 2011
    • + 35 Transazioni  ADO.NET rende disponibili tutte le funzionalità per l‟esecuzione di transazioni sulla base dati  E‟ necessario definire, al fine di poter eseguire una transazione, il suo TransactionScope.  Definisce la visibilità della transazione fra metodi differenti  Required: default, mantiene la medesima transazione fra metodi differenti.  RequiredNew: mantiene la medesima transazione o la crea se non presente  Suppress: annulla la transazione precedente  Per completare una transazione devo invocarne il metodo Complete.  Devo importare la dll System.Transactions ed il namespace omonimo. Dr. Paolo Casoto, Ph.D. - Copyright 2011
    • + 36 Ora il nostro codice è del tutto transazionale… …ma non funziona…infatti ACCESS non supporta l‟esecuzione delle transazioni  Indico di aver completato la transazione Dr. Paolo Casoto, Ph.D. - Copyright 2011
    • + 37 Transazioni  Il codice all‟interno di un blocco transazionale (o più blocchi se in modalità Required) è eseguito solo se non è stata lanciata alcuna eccezione durante l‟esecuzione.  In caso si presenti anche una sola eccezione, il sistema esegue automaticamente il rollback della transazione.  Ma come regolare il grado di isolamento fra le transazioni al fine di evitare l‟inconsistenza dei dati ?  In parte la soluzione è dipendente dai singoli DBMS adottati  In parte la possiamo definire andando a modificare il parametro IsolationLevel. Dr. Paolo Casoto, Ph.D. - Copyright 2011
    • + 38 Livelli di isolamento Dr. Paolo Casoto, Ph.D. - Copyright 2011
    • + 39 Ancora transazioni  Una alternativa alla definizione di blocchi di codice transazionale (che non è necessariamente limitato all‟ambito delle basi di dati) è quello di utilizzare transazioni locali.  Oggetti DbTransaction definiti per ciascuno specifico data provider e creati a partire da una connessione mediante il metodo BeginTransaction.  Ciascun oggetto DbTransaction consente l‟invocazione dei classici metodi Commit e Rollback che annullano le operazioni eseguite sulla base di dati, in accordo con lo specifico livello di isolamento. Dr. Paolo Casoto, Ph.D. - Copyright 2011
    • + 40 DbCommand  Consentono di inviare ad una connessione 3 diverse richieste:  Query parametriche: abbiamo già visto una serie di esempi di codice che fa uso di questo tipo di DbCommand, con type Text.  Stored procedure: è possibile invocare l‟esecuzione di una stored procedure presente all‟interno della base dati. La tipologia in questo caso è di tipo StoredProcedure.  Tabelle: consente il reperimento di una intera tabella presente all‟interno di una base di dati. La tipologia in questo caso è di tipo TableDirect.  Anche nel caso delle stored procedure è possibile valorizzare eventuali parametri mediante il metodo AddWithValue(nome, valore) Dr. Paolo Casoto, Ph.D. - Copyright 2011
    • + 41 DbCommand  Definito un comando posso eseguire 4 differenti tipologie di operazione sulla base di dati:  ExecuteNonQuery: modifiche, inserimenti, cancellazioni…ovvero tutte quelle operazioni che non restituiscono alcun risultato.  ExecuteReader: tutte le query che restituiscono un DataReader per l‟accesso ai dati.  ExecuteScalar: restituisce solamente, a partire da una query o da una stored procedure, il valore nella prima colonna della prima riga  Utilizzato generalmente per tutte le query di tipo COUNT, quale versione leggera di ExecuteReader  ExecuteXmlReader: disponibile solo su SqlCommand, è utilizzato per navigare codice XML memorizzato quale colonna di un DB SQL Server Dr. Paolo Casoto, Ph.D. - Copyright 2011
    • + Inserimento - ExecuteNonQuery 42 Conteggio – ExecuteScalar Dr. Paolo Casoto, Ph.D. - Copyright 2011
    • + 43 Stored Procedure  Nel caso di stored procedure finalizzate all‟aggiornamento, cancellazione, inserimento dei dati, anche se parametri, ma prive di output posso continuare ad utilizzare il metodo ExecuteNonQuery.  Nel caso, invece di s.p. finalizzate alla ricerca di dati è possibile utilizzare due alternative:  ExecuteReader, in maniera del tutto analoga a quanto avviene nell‟ambito delle query SQL  Utilizzando una particolare tipologia di parametro, detto parametro di output  Simile per concetto al passaggio di valori per riferimento, dove la s.p. può depositare un output scalare  Non possiamo provarlo su ACCESS, anche in questo caso si tratta di una funzionalità non supportata. Dr. Paolo Casoto, Ph.D. - Copyright 2011
    • + 44 DbDataReader  I campi delle righe memorizzate all‟interno di un DbDataReader possono essere acceduti utilizzando due metodologie di indirizzamento:  Posizione (con partenza da 0)  Titolo della colonna selezionata (o dell‟alias nel caso di query basate su funzioni SQL come il COUNT)  La prima delle due metodologie ha una efficienza pari a sette volte la seconda (0.09s vs 0. 63s) rispetto ad un numero di 1M invocazioni.  La miglior soluzione è quella di utilizzare costanti con nomi mnemonici riconducibili a nomi delle colonne ma con valori numerici. Dr. Paolo Casoto, Ph.D. - Copyright 2011
    • + 45 DbParameter  Consentono di rimpiazzare, come abbiamo visto, un placeholder all‟interno di una query SQL o della invocazione di una stored procedure parametrica.  DbType: definisce il tipo di dato nativo rappresentato dal parametro. Funge da lingua ponte fra i tipi disponibili nei diversi DBMS ed i tipi resi disponibili dal CLR di .NET.  Direction: determina se si tratta di un parametro di input, di output, bidirezionale o di ritorno.  IsNullable: determina se il parametro può assumere valore NULL  ParameterName: nome del parametro  Size: dimensione massima in byte dei dati di tipo testuale  Value: valore effettivo associato al parametro, in input o output. Dr. Paolo Casoto, Ph.D. - Copyright 2011
    • + 46 Accesso ai dati in modalità disconnessa  Tutti gli oggetti che abbiamo avuto modo di vedere fin qui si basano su una stretta interconnessione fra il chiamante e la base di dati che rende disponibili i dati.  Lo stesso concetto di DbDataReader è, come abbiamo detto, un cursore lato server sui dati, che impegna, durante la sua navigazione, sia risorse lato server sia risorse lato client.  La modalità disconnessa consente invece di lavorare sui dati replicando parte della base dati nella memoria del chiamante e limitando le interazioni ed il consumo di banda fra chiamante e DBMS.  Più in generale i dati potrebbero non derivare da un DBMS, bensì da un file Excel o XML Dr. Paolo Casoto, Ph.D. - Copyright 2011
    • + 47 Accesso ai dati in modalità disconnessa  Astraggo dagli oggetti e dai metodi che abbiamo visto nel caso della modalità connessa.  Gli oggetti di alto livello utilizzati si preoccupano, nelle modalità opportune, di stabilire le connessioni alla base dati e di effettuare tutte le operazioni necessarie al reperimento o alla modifica dei dati stessi.  L‟oggetto alla base del modello di interazione è il DataSet, un insieme di dati suddivisi in DataTable e, a loro volta, in DataRow e DataColumn.  Un DataSet è collegato ai corrispettivi dati a livello relazionale da un cosiddetto data adapter, che funge da ponte fra il DataSet logico visto dal programmatore e la effettiva base di dati relazionale presente nel DBMS. Dr. Paolo Casoto, Ph.D. - Copyright 2011
    • + 48 Accesso ai dati in modalità disconnessa  Un DataSet può inoltre rappresentare anche relazioni fra le tabelle, vincoli sulle singole colonne, chiavi primarie e viste.  Le informazioni necessaria alla mappatura di una base dati su un DataSet possono essere fornite mediante codice, file XML di configurazione o tool grafici resi disponibili da Visual Studio. Dr. Paolo Casoto, Ph.D. - Copyright 2011
    • + 49 Accesso ai dati in modalità disconnessa  Il layer per la modalità disconnessa si occupa la posto del programmatore di tutte le problematiche legate alle prestazioni ed all‟efficienza del processo, mantenendo aperte le connessioni alla base dati per il minor tempo possibile.  Il richiedente ottiene a seguito di una richiesta un DataSet locale, sul quale può andare anche ad effettuare modifiche, cancellazioni o inserimenti.  I dati non sono acceduti mediante un cursore remoto sul server bensì sono presenti all‟interno della memoria del tier richiedente.  Un DataSet è costituito da un insieme di tre collezioni:  Tabelle, relazioni fra tabelle e proprietà estese del DataSet. Dr. Paolo Casoto, Ph.D. - Copyright 2011
    • + 50 DataSet  In aggiunta a tabelle, relazioni fra tabelle vi sono alcune particolari proprietà che possono caratterizzare il DataSet  Proprietà estese: metadati che possono essere utilizzati nel corso del ciclo di vita del DataSet  Nome dell‟azienda, nome dell‟applicazione, intervallo di aggiornamento dei dati, et al.  CaseSensitive: indica come il confronto fra stringhe all‟interno delle DataTable debba essere eseguito.  DataSetName: nome del dataset.  EnforceConstraints: indica se tutti i vincoli debbano essere rispettati ad ogni operazione di inserimento / modifica. Per default è TRUE.  HasErrors: indica se vi sono errori di validazione nei dati contenuti all‟interno del DataSet. Metodo di sola lettura.  Remotingformat: formato di serializzazione del contenuto del DataSet (e.g.: XML, binario, et al.). Dr. Paolo Casoto, Ph.D. - Copyright 2011
    • + 51 Manipolare i DataSet  I seguenti metodi consentono la manipolazione di un DataSet:  AcceptChanges: esegue il commit di tutte le modifiche al DataSet dal suo caricamento o dall‟ultima esecuzione del metodo AcceptChanges.  Clear: svuota tutti i dati presenti all‟interno del DataSet.  Clone: clona la struttura di un DataSet, ma non i dati. Diverso da Copy che invece esegue una copia anche dei dati.  GetChanges: restituisce le sole righe modificate dalla ultima sincronizzazione, anche per tipologia (rimosse, inserite, modificate)  HasChanges: verifica se vi sono modifiche rispetto all‟ultima sincronizzazione del DataSet.  Merge: fonde due DataSet. Dr. Paolo Casoto, Ph.D. - Copyright 2011
    • + 52 Manipolare i DataSet  I seguenti metodi consentono la manipolazione di un DataSet:  RejectChanges: annulla tutte le modifiche dall‟ultima sincronizzazione del DataSet.  ReadXml: definisce la struttura di un DataSet e lo popola a partire da un documento XML che funge da schema.  WriteXml: consente di serializzare il contenuto di un DataSet all‟interno di uno stream di dati sotto forma di documento XML. Dr. Paolo Casoto, Ph.D. - Copyright 2011
    • + 53 Esempio: Passo 1 Creazione manuale Proprietà estese Forzo il rispetto dei vincoli Dr. Paolo Casoto, Ph.D. - Copyright 2011
    • + 54 DataColumn  Rappresenta una colonna di una DataTable presente all‟interno di un DataSet.  L‟insieme delle DataColumn di una DataTable costituisce lo schema della tabella stessa.  Una DataColumn mappa caratteristiche, tipo di dati e vincoli della specifica colonna fisica alla quale si riferisce.  Alcune proprietà caratteristiche di un DataColumn:  AllowDBNull: consente valori NULL sulla colonna;  AutoIncrement: gestione dei campi auto incrementali, ad esempio nel caso di chiavi primarie autogenerate.  Caption: etichetta della colonna  Utilizzata anche in fase di visualizzazione delle informazioni. Dr. Paolo Casoto, Ph.D. - Copyright 2011
    • + 55 DataColumn  ColumnMapping: tag da utilizzare per la mappatura della colonna su XML  ColumnName: nome della colonna all‟interno della DataTable.  DataType: tipo di dato della colonna (e.g.: Boolean, String, float, int et al.).  DefaultValue: valore predefinito della colonna.  Ordinal: posizione della colonna all‟interno della collezione di colonne della DataTable.  ReadOnly: colonna non modificabile.  Unique: vincolo di unicità sui valori della colonna. Dr. Paolo Casoto, Ph.D. - Copyright 2011
    • + 56 Esempio: Passo 2 Chiave intera con nome “id”, etichetta “ID”, autogenerata con un contatore che avanza di 1 valore alla volta Campi stringa non nulli Dr. Paolo Casoto, Ph.D. - Copyright 2011
    • + 57 Esempio: Passo 3 Abbiamo creato una tabella “Utenti” con le 4 colonne precedentemente definite La tabella è ancora priva di dati e scollegata dal DataSet Dr. Paolo Casoto, Ph.D. - Copyright 2011
    • + 58 DataRow  Rappresenta una riga di dati all‟interno di una DataTable, in accordo con l‟insieme delle colonne che costituiscono la tabella.  I seguenti metodi consentono di manipolare le DataRow presenti all‟interno di una tabella:  HasErrors, GetColumnsInError, GetColumnError, ClearErrors, RowError: consentono di verificare la presenza di eventuali errori all‟interno della riga. In particolare è possibile verificare per quale colonna siano stati violati i vincoli imposti al tipo di dato, alla unicità, alla presenza di valori NULL o di vincoli di integrità referenziale.  ItemArray: restituisce un array di oggetti con i valori assunti dalla riga per ciascuna colonna Dr. Paolo Casoto, Ph.D. - Copyright 2011
    • + 59 DataRow  I seguenti metodi consentono di manipolare le DataRow presenti all‟interno di una tabella:  RowState: indica se la riga è stata modificata, cancellata, inserita o integra rispetto alla ultima sincronizzazione del DataSet.  AcceptChanges: accetta le modifiche alle righe dall‟ultima invocazione di AcceptChanges.  RejectChanges: rifiuta le modifiche apportate alla riga dall‟ultima invocazione di AcceptChanges.  BeginEdit, EndEdit, CancelEdit: gestione delle operazioni di modifica della riga.  IsNull: verifica se il valore di una riga per una specifica colonna è NULL. Dr. Paolo Casoto, Ph.D. - Copyright 2011
    • + 60 Esempio: Passo 4 Per creare un nuova riga DEVO invocare un metodo dell‟oggetto DataTable. Il costruttore di DataRow non è pubblico !!! Posso referenziare le colonne per nome o per posizione E se sbaglio genero una eccezione !!! Aggiungo la riga alla tabella Dr. Paolo Casoto, Ph.D. - Copyright 2011
    • + 61 Lo stato di una DataRow Aggiungo la riga alla tabella Dr. Paolo Casoto, Ph.D. - Copyright 2011
    • + 62 Esempio: Passo 5 Dr. Paolo Casoto, Ph.D. - Copyright 2011
    • + 63 La versione di una DataRow Dr. Paolo Casoto, Ph.D. - Copyright 2011
    • + 64 La versione di una DataRow  Le operazioni eseguite su una DataRow in accordo con il suo DataRowState possono modificare la versione della riga stessa in questo modo:  Se è modificato un valore della riga dopo la chiamata al metodo DataRow.BeginEdit le versioni Current e Proposed del valore della riga sono disponibili.  L‟invocazione del metodo DataRow.CancelEdit elimina il valore Proposed.  L‟invocazione del metodo DataRow.EndEdit fa si che il valore Current di una riga assuma il valore Proposed.  L‟invocazione di DataRow.AcceptChanges o DataTable.AcceptChanges rende il valore Original identico a Current. Dr. Paolo Casoto, Ph.D. - Copyright 2011
    • + 65 DataTable  Oggetto utilizzato per mappare il concetto di tabella, riprende molti degli attributi e dei metodi della classe DataSet.  Un DataSet è, fra le varie cose, un insieme di DataTable. Ciascun DataTable, a sua volta, è costituito da un insieme di DataColumn e DataRow, che ne descrivono la struttura ed i valori attuali.  Fra i metodi e gli attributi più significativi è utile segnalare:  ChildRelations: restituisce le relazioni figlio della tabella.  Constraints: restituisce l‟insieme dei vincoli che caratterizzano la tabella  DataSet: restituisce il DataSet del quale la tabella è parte. Dr. Paolo Casoto, Ph.D. - Copyright 2011
    • + 66 DataTable  DefaultView : restituisce un vista personalizzata sulla tabella, ad esempio mediante l‟introduzione di specifici filtri.  ParentRelations: restituisce le relazioni padre rispetto alla tabella.  PrimaryKey: insieme delle colonne che fungono da chiavi primarie della tabella.  TableName: nome della tabella.  La definizione delle colonne che fungono da chiavi primarie si esegue mediante la creazione di un array di colonne e la sua associazione all‟attributo PrimaryKey di tipo array. Dr. Paolo Casoto, Ph.D. - Copyright 2011
    • + 67 DataTable vs DbDataReader  Abbiamo visto come i DbDataReader siano caratterizzati da una lettura mediante un ciclo while fino all‟esaurimento dei dati disponibili.  La lettura può avvenire solo in una direzione e mantiene una connessione attiva con il server, che funge da cursore remoto.  Al contrario un DataSet può essere navigato, così come le DataTable in esso contenute, mediante una serie di cicli for annidati.  I dati possono essere letti nella direzione preferita, anche più volte, senza mantenere alcun legame con il DBMS lato server. Dr. Paolo Casoto, Ph.D. - Copyright 2011
    • + 68 DataTableReader  Al fine di uniformare l‟accesso ai dati anche in modalità disconnessa è possibile utilizzare per l‟accesso ad una DataTable un oggetto di tipo DataTableReader.  Analogo al DbDataReader che abbiamo incontrato nella modalità connessa, consente di analizzare in maniera sequenziale le singole righe della tabella.  A differenza del DbDataReader in questo caso i dati solo letti utilizzando il DataSet memorizzato localmente quale cursore rispetto ai dati.  Ideale per navigare all‟interno di una DataTable o di un intero DataSet in modalità agnostica rispetto ai concetti di DataColumn e DataRow. Dr. Paolo Casoto, Ph.D. - Copyright 2011
    • + 69 DataTableReader Dr. Paolo Casoto, Ph.D. - Copyright 2011
    • + 70 Serializzare i dati su XML  Come abbiamo visto parlando di DataSet, gli oggetti delle classi DataSet e DataTable possono essere serializzati in formato XML (e binario).  E‟ possibile serializzare i dati contenuti all‟interno di un DataSet o di una DataTable, i quali saranno salvati all‟interno di un file XML  Metodo WriteXml  E‟ possibile serializzare lo schema di un DataSet o di una DataTable mediante un file XML aderente allo standard XML Schema, con estensione xsd.  Metodo WriteXmlSchema  In fase di lettura i dati possono essere ripristinati all‟interno del DataSet o della DataTable mediante il metodo ReadXml. Dr. Paolo Casoto, Ph.D. - Copyright 2011
    • + 71 Esempio di serializzazione Dr. Paolo Casoto, Ph.D. - Copyright 2011
    • + 72 Esempio di serializzazione - XML Dr. Paolo Casoto, Ph.D. - Copyright 2011
    • + 73 Esempio di serializzazione - XSD File .xsd visualizzato mediante Visual Studio Dr. Paolo Casoto, Ph.D. - Copyright 2011
    • + 74 Relazioni fra le tabelle  E‟ possibile mediante ADO.NET in modalità disconnessa definire relazioni fra colonne di DataTable appartenenti ad un DataSet  Mediante il metodo Add della proprietà Relations di un oggetto DataSet  Il metodo assume come argomenti due DataColumn appartenenti a due DataTable ed un eventuale nome identificativo della redazione.  Data un DataRow è possibile disporre dell‟array delle DataRow collegate sulla tabella relazionata mediante il metodo GetChildRows, che accetta in input il nome della relazione. Dr. Paolo Casoto, Ph.D. - Copyright 2011
    • + 75 Relazioni fra le tabelle  Parimenti è possibile navigare una relazione in senso opposto mediante il metodo GetParentRows, che restituisce le righe all‟altro capo della relazione fra le tabelle.  Le relazioni costituiscono solo uno strumento di navigazione fra le righe di DataTable differenti  Per imporre vincoli sui dati quali vincoli di chiave esterna è possibile aggiungere al DataSet specifici Constraint.  Sui Constraints posso andare a definire le regole per la gestione della propagazione di aggiornamenti e cancellazioni. Dr. Paolo Casoto, Ph.D. - Copyright 2011
    • + 76 Constraints Ogni tanto un po‟ di esempi in VB  Dr. Paolo Casoto, Ph.D. - Copyright 2011
    • + 77 Agganciamo una DataTable ad un componente grafico  Utilizziamo ora le componenti grafiche standard offerte da .NET per rendere fruibili i dati agli utenti  Creiamo un nuovo progetto, questa volta finalizzato alla creazione di una applicazione con interfaccia grafica  All‟interno della form principale collochiamo un oggetto di tipo DataGridView, una griglia per la visualizzazione dei dati associabile ad uno specifico DataSet.  L‟oggetto DataGridView analizza tutte le righe e le colonne che costituiscono la DataTable e predispone il riempimento con i valori attuali. Dr. Paolo Casoto, Ph.D. - Copyright 2011
    • + 78 Esempio – Passo 1 Dr. Paolo Casoto, Ph.D. - Copyright 2011
    • + 79 Esempio – Passo 2 Lo stato della tabella è legato alla visualizzazione Dr. Paolo Casoto, Ph.D. - Copyright 2011
    • + 80 Esempio – Passo 3 Rimuove la prima riga se presente Aggiunge una riga Dr. Paolo Casoto, Ph.D. - Copyright 2011
    • + 81 Esempio – Passo 4 Dr. Paolo Casoto, Ph.D. - Copyright 2011
    • + 82 Filtrare il contenuto di una DataTable  Il metodo Select consente di applicare un criterio di filtraggio ai dati contenuti all‟interno di una TableData.  Il filtro opera come la clausola WHERE delle query SQL con una sintassi semplificata  E.g.: Nome = „Paolo‟  dataTable.Select(“Nome = „Paolo‟”);  E‟ possibile aggiungere all‟opzione di filtraggio una colonna rispetto alla quale eseguire l‟ordinamento dei risultati (ascendente o discendente).  dataTable.Select(“Nome = „Paolo‟”,”Cognome”); Dr. Paolo Casoto, Ph.D. - Copyright 2011
    • + 83 Esempio – Passo 5 Dr. Paolo Casoto, Ph.D. - Copyright 2011
    • + 84 Esempio – Passo 6 Dr. Paolo Casoto, Ph.D. - Copyright 2011
    • + 85 Esempio – Passo 7 Modifichiamo il valore di una riga della tabella alla pressione di un pulsante La modifica sarà propagata in automatico anche al DataGridView Dr. Paolo Casoto, Ph.D. - Copyright 2011
    • + 86 Esempio – Passo 8 Il valore della prima riga risulta modificato Dr. Paolo Casoto, Ph.D. - Copyright 2011
    • + 87 Esempio – Passo 9 Aggiungiamo un evento che comporta la cancellazione di una riga al clic all‟interno di una delle celle della riga stessa Dr. Paolo Casoto, Ph.D. - Copyright 2011
    • + 88 Esempio – Passo 10 Dr. Paolo Casoto, Ph.D. - Copyright 2011
    • + 89 DataView  Corrispettivo lato client del concetto di vista reso disponibili da molti DBMS.  Estrarre da una delle tabelle del DataSet un insieme di dati in maniera programmatica.  I vantaggi dell‟utilizzo delle viste sono la possibilità di utilizzare più elementi grafici di visualizzazione a partire dai medesimi dati.  Per la creazione di una DataView è necessario utilizzare il costruttore passando come parametro la tabella rispetto alla quale la vista fa riferimento.  Il campo RowFilter consente di definire il filtro da applicare alle righe della tabella. Dr. Paolo Casoto, Ph.D. - Copyright 2011
    • + 90 Ma come riempire un DataSet ?  Abbiamo visto come generare un DataSet e riempirlo in maniera programmatica o mediante il caricamento di un file XML / binario precedentemente salvato.  Ma come si può interagire con la sorgente reale dei dati, in lettura e scrittura (modifica, creazione, cancellazione) ?  Mediante l‟utilizzo di un oggetto della classe DbDataAdapter  Basato su una gerarchia reale istanziata rispetto allo specifico data provider (e.g.:SQL Server, ODBC, et al.) il DbDataAdapter riempie il DataSet e consente la persistenza e/o l‟aggiornamento delle singole DataTable Dr. Paolo Casoto, Ph.D. - Copyright 2011
    • + 91 DbDataAdapter  Per eseguire le funzionalità di lettura ed aggiornamento dei dati gli oggetti della classe DbDataAdapter e delle classi derivate utilizzano i medoti:  Fill: esegue le query di ricerca necessaria a popolare le DataTable che costituiscono il DataSet  Update: esegue le query di aggiornamento, cancellazione ed inserimento necessarie per la sincronizzazione del DataSet con la base dati reale.  Ciascuna operazione descritta è basata su un insieme di 4 DbDataCommand:  SelectCommand  InsertCommand  UpdateCommand  DeleteCommand Dr. Paolo Casoto, Ph.D. - Copyright 2011
    • + 92 Vantaggi  Non spetta al programmatore occuparsi di connessioni, transazioni, gestione delle eccezioni e dei casi critici  Il layer si assume tutti questi oneri, lasciando al programmatore il compito di riempire ed aggiornare il DataSet.  Il DbDataAdapter, poiché trasparente rispetto alla connessione per il programmatore, potrebbe essere utilizzato in linea teorica anche per l‟accesso a dati presenti all‟interno di differenti tipologie di DBMS  E.g.: tabelle su MySQL insieme a tabelle su SQL Server Dr. Paolo Casoto, Ph.D. - Copyright 2011
    • + 93 Ma se il DataSet contiene più di una tabella ?  Andremo a definire (o meglio lo deleghiamo a Visual Studio) uno specifico DbDataAdapter per ciascuna DataTable  Ciascuna DataTable può a sua volta essere relazionata alle altre mediante specifiche relazioni, definite all‟interno del DataSet come oggetti DataRelation.  Grazie alle relazioni posso navigare all‟interno delle DataTable anche muovendomi trasversalmente lungo la base di dati, seguendo le relazioni di chiave esterna. Dr. Paolo Casoto, Ph.D. - Copyright 2011
    • + 94 Come definire un DataSet in Visual Studio 2010 – Passo 1 Per ora ignoriamo le altre tre possibilità Dr. Paolo Casoto, Ph.D. - Copyright 2011
    • + 95 Come definire un DataSet in Visual Studio 2010 – Passo 2 Per ora ignoriamo l‟Entity Framework Dr. Paolo Casoto, Ph.D. - Copyright 2011
    • + 96 Come definire un DataSet in Visual Studio 2010 – Passo 3Definiamo la stringa di connessioneche utilizzeremo per l‟accesso alla SENZAbase di dati PREOCCUPARCI DI APRIRLA O Dr. Paolo Casoto, Ph.D. - Copyright 2011 CHIUDERLA !!!!
    • + 97 Come definire un DataSet in Visual Studio 2010 – Passo 4 Selezioniamo tabelle, campi e viste che vorremmo utilizzare nel nostro DataSet Il sistema genera automaticamente la maggior parte del codice che ci serve per il reperimento e l‟aggiornamento delle informazioni Dr. Paolo Casoto, Ph.D. - Copyright 2011
    • + 98 Come definire un DataSet in Visual Studio 2010 – Passo 5  In aggiunta alla definizione del DbDataAdapter da utilizzare per popolare uno specifico DataSet, la procedura automatica di Visual Studio consente di generare un insieme di tipi dato (classi) per la manipolazione diretta delle entità del DataSet  Strongly Typed Data Set, Data Table e DataRow  Consentono, nelle sottoclassi, di accedere agli specifici attributi dell‟oggetto in maniera semplice ed efficace. Dr. Paolo Casoto, Ph.D. - Copyright 2011