Ado net (versione 1 e 2)

79
Ing. Felice Pescatore [email protected] Microsoft ADO.NET ActiveX Data Object .NET

description

 

Transcript of Ado net (versione 1 e 2)

2. ADO.NET: Compendi Consigliati Autori: msdn2.microsoft.com/it-it/library/default.aspx Francesco Balena www.ugidotnet.orgDino Esposito www.aspitalia.comMarco Bellinaso www.dotnet2themax.it David Sheppa 3. ADO.NET: introduzioneADO.NET il componente per laccesso ai dati del Microsoft .NET Framework.Si tratta di una evoluzione del precedente componente ADO con cui ha pochi punti in comune e rappresenta una vera e propria rivoluzione per svariati motivi che andremo ad analizzare.ADO.NET formato da una collezione di classi, interfacce, strutture etipi,che gestiscono laccesso ai dati allinterno del .NET framework, di cuisono parte integrante, e sono organizzate in namespace a partire daSystem.Data. 4. ADO.NET: ado.net vs. ado (1)Caratteristiche salienti di ADO Architettura Connessa; Legato al modello fisico dei dati; RecordSet il contenitore finale dei dati ricavati; RecordSet in pratica una tabella contenete tutti i dati: Per ottenere dati da pi tabelle necessario effettuare un JOIN; I Dati ottenuti sono piatti, sono perse le relazioni ed possibile consultarli solo in modo sequenziale; I dati sono converti nei corrispettivi formati COM/COM+ ; I dati vengono scambiati attraverso COM-marshalling Non sempre il formato binario di rappresentazione dei dati (DCOM,binary) riesce a superare i firewall. 5. ADO.NET: ado.net vs. ado (2)Caratteristiche salienti di ADO.NET Progettato per Accesso Disconnesso Modello di dati organizzato logicamente Il DataSet sostituisce il RecordSet DataSet pu contenere pi tabelle Ottenere dati da pi tabelle non richiede un JOIN; Le relazioni tra le tabelle sono preservate cos come relazionale lamodalit di accesso ai dati; I tipi di dati sono mappati attraverso un XML schema; Nessuna conversione dei tati richiesti XML, come HTML, puro testo e permette di passare agevolmente i firewall; 6. ADO.NET: ado.net vs. ado (3)XxxConnection Connection XxxTransaction ADO.NETCommand XxxCommand ADODataSetRecordset XxxDataReader XxxDataAdapter XXX sar sosituito dal prefisso relativo allRDBMS scelta. Ad esempio nel caso di SQL Server si avranno: SQLConnection, SQLTransaction, ecc. 7. ADO.NET: architettura connessa vs architettura disconnessa La nuova architettura XxxDataReader Disconnessa di ADO.NET DataSet consente di recuperare i dati dalla relativa fonte e crarne una rappresentazione in memoria su cui XxxCommand effettuare le elaborazioni, una sorta XxxDataAdapter di cache-database contenuto nel RecordSet. Questo permette di effettuare tutte le operazioni senza XxxConnection XxxConnection essere connessi direttamente alla fonte dati e, successivamente, inviare gli aggiornamenti Data Data 8. ADO.NET: architettura applicativa 9. ADO.NET: vantaggiAlta Interoperabilit grazie alluso di XML: Standard aperti per i dati che si autodescrivono Informazioni facilmente leggibili Uso interno della mappatura ma utilizzabile esternamente, per poterleggere, scrivere e sostituire i dati;Elevata Scalabilit grazie alluso dei DataSet disconnessi: Le connessioni sono mantenute solo per brevi periodi Non necessario effettuare il lock del database (comunque supportato attraverso i ServiceComponents e comunque in modalit ottimistica-Optimistic); Modalit pensata per lavorare secondo il paradigma delle web application;Manutenibilit Separazione tra i dati e la loro rappresentazione 10. ADO.NET: architetturaCome tutti gli altri componenti del .NET Framework, ADO.NET consiste di un insieme dioggetti che interagiscono fra loro per svolgere una determinata funzione ( appunto unframework). ADO.NET composto da due componenti fondamentali: il Data (Managed) Provider che mantiene la connessione con la sorgente dati fisica; il DataSet (e pi in generale i Data Storage), che rappresenta i dati attuali, ovvero i dati su cui si sta lavorando..NET Data ProviderData Consumer .NET Data StorageConnection DataSet WinForm Command DataTables WebFormDataAdapter XMLDataDataReader XMLDataSchema Altri XML Entrambi i componenti possono Data Sourcecomunicare con i Data Consumers , ovvero i fruitori dei loro servizi, come, ad esempio una WinForm o una WebForm. 11. ADO.NET: architettura.NET Application DataSetSystem.Data.Oracle System.Data.SqlClient System.Data.OleDb System.Data.Odbc OLE DB OLE DB Provider ODBC Non-relationalOracleSQL Server Other DBMSsources 12. ADO.NET: Data ProviderAttraverso il Data Provider possibile ottenere/inviare dati da/a un qualsiasi tipodi sorgente dati: Relazionale XML CustomOgni sorgente dati ha un proprio Data Provider ed ognuno di essi espone gli stessimetodi (implementando le stesse interfacce o classi base) di base con opportuniprefissi specifici.Il Data Provider comprende vari tipi di oggetti: xxxConnection: rappresenta la connessione fisica con la sorgente dati xxxCommand: rappresenta un comando da eseguire sulla sorgente dati (ad es. unistruzione SQL) xxxDataReader: permette di ottenere in modo veloce, read-only e forward-only i datidalla sorgente dati xxxDataAdapter fornisce il meccanismo di interazione tra la connessione e il data set 13. ADO.NET: SQL Data Provider Object ModelSqlConnectionSqlCommand System.Xml.XmlReader SqlDataReader SqlParameterCollectionObject SqlParameterCommon Language Runtime SQL CLIENT TDSSQL PARSERSERVER 14. ADO.NET: OleDB Data Provider Object ModelOleDbConnection.CreateCommand.ExecuteReaderOleDbCommand .Connection.ParametersOleDbDataReaderOleDbParameterCollection .Add .Item.CreateParameter .ItemObject OleDbParameterCommon Language Runtime OleDbProviderOLEDB Data SourceManagedRelazionaleProvidere non 15. ADO.NET: ODBC Data Provider Object ModelOdbcConnection.CreateCommand .ExecuteReader OdbcCommand.Connection.ParametersOdbcDataReaderOdbcParameterCollection.Add .Item.CreateParameter.ItemObjectOdbcParameterCommon Language RuntimeODBC DRIVERODBC ManagedData SourceRelazionale Provider 16. ADO.NET: DB2 Data Provider Laccesso a DB2 di IBM pu avvenire attraverso i provider OleDb o ODBC illustratiprima oppure attraverso uno specifico managed provider sviluppato da IBM Application ApplicationApplication System.Data.OleDbMicrosft.Data.ODBC IBM.Data.DB2OLE DB .NetODBC .NetDB2 .Net DataData Provider Data Provider ProviderOleDbConnection OdbcConnection DB2Connection OleDbCommandOdbcCommandDB2CommandOleDbAdapterOdbcDataAdapterDB2DataAdapterOleDbDataReader OdbcDataReader DB2DataReaderIBM DB2 OLEIBM DB2 DB ProviderODBC DriverDB2 17. ADO.NET: Oracle Data Provider Nel caso di Oracle si ha uno scenario ulteriormente diverso con 2 provider specifici: Microsoft .NET Data Provider per Oracle, prodotto da Microsoft e usa gli strumenti client di Oracle Oracle Data Provider per .NET (ODP.NET), sviluppato da Oracle, presenta unintegrazione completa esponendo tutte le caratteristiche di un Oracle DB In p disponibile lOracle Connect per .NET per luso con OleDB e Odbc 18. ADO.NET: Data Provider, Classe Connection La classe Connection (simile a quella presente in ADO classico) implementa linterfaccia IDBConnection; Per poter effettuare la connessione bisogna specificare una Connection String, che: Pu essere specificata mediante un costruttore parametrico; Utilizza le stesse keyword di ADODB; [Visual Basic] Dim conSQL As SqlConnection = New SqlConnection("Data Source=localhost;Integrated & _ Security=SSPI;Initial Catalog=northwind") SqlConnection.Open() [C#] SqlConnection SqlConnection = new SqlConnection("Data Source=localhost; Integrated Security=SSPI; Initial Catalog=northwind"); SqlConnection.Open(); 19. ADO.NET: Data Provider, Classe Command Una volta creata una connessione possibile fare una interrogazione alla sorgente dati e ottenerne una rappresentazione in memoria. Per realizzare ci si fa ricorso alla classe Command che implementa linterfaccia IDBCommand In base al risultato atteso possiamo eseguire un comando attraverso metodispecificatamente ottimizzati: ExecuteReader() da utilizzare quando previsto un result set (DataReader) come ritorno; ExecuteScalar() da utilizzare per aggregazioni o risultati di calcoli; ritorna solo la prima colonna della prima riga, gli altri dati vengono persi; ExecuteNonQuery() ottimizzato per query che non ritornano result set ma solo parametri di ritorno onumero di record modificati; ExecuteXMLReader() specifico per laccesso a dati di tipo XML; Le prime tre versioni di Execute vanno usate adeguatamente in modo da garantire performance ottimali nelle proprie applicazioni. 20. ADO.NET: Data Provider, Classe Command e Query libere Dim sqlConn As SQLConnection Dim sqlCmd As SQLCommandVediamo un Dim rowsAffected As IntegeresempioTrycompleto diCreo la connessioneutilizzo dellasqlConn = New SQLConnection(myConnString)classe Creo il comandoCommand.sqlCmd = New SQLCommand() specifico il tipo di comandoUn oggettoWith sqlCmdCommand pu .CommandType = CommandType.Textessere creato in.CommandText = "Insert Customers (Alias, CustomerName) _ Values (myAlias,myName)"due modi:.Connection = sqlConn Mediante il End Withcostruttore; apro la connessione Mediante il sqlConn.Open()metodo eseguo il comando, vengono ritornate le righe inseriteCreateCom rowsAffected = sqlCmd.ExecuteNonQuery()mand daCatch e As Exceptioninocaregestisco leccezione sulloggetto Finallyconnessionechiudo la connesionesqlConn.Close() End Try 21. ADO.NET: Data Provider, Classe Command & Stored Procedure Attraverso la classe Command possibile invocare una StoredProcedure (se lasorgete dati le preveda). Per fare ci bisogna: Creare un oggetto Command; Impostare CommandType al valore StoredProcedure; Impostare la propriet CommandText; Usare il metodo Add per creare e aggiungere parametri; Impostare la propriet ParameterDirection; Invocare ExecuteReader; Consumare i record, e chiudere il DataReader; Leggere i parametri di output e il valore di ritorno. Nel caso in cui sia necessario impostare a NULL un paramero di input possibileutilizzare DBNull.Value. 22. ADO.NET: Data Provider, Classe Command & Stored Procedure sqlConn = New SQLConnection(myConnString)Creo il Command sqlCmd = New SQLCommand() Specifico la Stored Procedure e la connessioneWith sqlCmd .CommandType = CommandType.StoredProcedure .CommandText = "InsertCustomer" .Connection = sqlConnEnd With Definisco e aggiung un parametro alla relativa collectionparam = sqlCmd.Parameters.Add(New SQLParameter("@p", SQLDBType.NVarChar, 100)With param .Direction = ParameterDirection.Input Setto il valore del parametro .Value = xyz"End With Aggiungo i parametri rimanenti Apro la connessionesqlConn.Open() Eseguo il comandorowsAffected = sqlCmd.ExecuteNonQuery() 23. ADO.NET: Data Provider, Classe DataReader Come accennato un DataReader permette di ottenere in modo veloce, read-only e forward-only i dati dalla sorgente. Si tratta in pratica del duale del Recordset di ADO. La classe DataReader implementa le interfacce IDataReader e IDataRecord Attraverso il DataReader possibile: Avanzare alla posizione successiva mediante il metodo Read(), che ritorna True finch non si sono consumati tutti i dati; Accedere ai dati nelle singole colonne per indice o per nome del campo; Accedere ai dati attraverso metodo accessori dedicati ai tipi di dato contenuti: GetDateTime(), GetDouble(), GetGuid(), GetInt32() 24. ADO.NET: Data Provider, Classe DataReader[Visual Basic]Dim myReader As SqlDataReader = myCommand.ExecuteReader()Do While myReader.Read() Console.WriteLine(vbTab & "{0}" & vbTab & "{1}", myReader.GetInt32(0),myReader.GetString(1))LoopmyReader.Close()[C#]SqlDataReader myReader = myCommand.ExecuteReader();while (myReader.Read()) Console.WriteLine("t{0}t{1}", myReader.GetInt32(0), myReader.GetString(1));myReader.Close();E importante sottolineare che un DataReader impegna la propria connessione, quindi: Non possibile utilizzarla per eseguire comandi; Dobbiamo ricordarci di chiuderlo mediante il metodo Close(); 25. ADO.NET: Data Provider, Classe XmlReaderVediamo come utilizzare lExecuteXmlReader() per ottenere un XmlReader:[Visual Basic]Dim custCMD As SqlCommand = New SqlCommand("SELECT * FROM Customers FOR XML_ AUTO, ELEMENTS", nwindConn)Dim myXR As System.Xml.XmlReader = custCMD.ExecuteXmlReader()[C#]SqlCommand custCMD = new SqlCommand("SELECT * FROM Customers FOR XML AUTO,ELEMENTS", nwindConn);System.Xml.XmlReader myXR = custCMD.ExecuteXmlReader(); 26. ADO.NET: Data Provider, TransazioniLe Transizioni sono utilizzate per rendere atomiche una serie di operazioni su un insieme di dati, in modo che vengano realizzate tutte o nessuna. [VB.NET]Le Transizioni Locali sono OleDbConnection conn = new OleDbConnection();lequivalente imperativo di quelle conn.Open("...");native SQL OleDbTransaction tx = conn.BeginTransaction();(BEGIN/COMMINT TRAN)OleDbCommand cmd = conn.CreateCommand();contenute,ad esempio, cmd.CommandText = "...";nelle Stored Procedure. cmd.Transaction = tx;cmd.ExecuteNonQuery();Vediamo con un esempio pratico tx.Commit();come realizzare una transizionecon Ado.Net: [C#] SqlConnection conn = new SqlConnection(); conn.Open("..."); SqlTransaction tx = conn.BeginTransaction();SqlCommand cmd = conn.CreateCommand();cmd.CommandText = "...";cmd.Transaction = tx;cmd.ExecuteNonQuery(); tx.Commit(); 27. ADO.NET: Data Provider, ExceptionEventuali errori durante lesecuzione di operazioni sulla fonte dati vengonointercettati attraverso le eccezioni.Ogni Managed providers implementa le proprie eccezioni derivanti daSqlExceptionSqlErrorLevento di base da gestire per cattuare le eccezioni InfoMessage, gestibileattraverso il delegato SqlInfoMessageEventHandler public static void myHandler(object conn, SqlInfoMessageEventArgs e) Metodo da { passare al delegato Console.WriteLine("caught a SQL warning"); for (int i=0; i < e.Errors.Count; i++) { Console.WriteLine("Index#" + i + "n" + "Warning:" + e.Errors[i].ToString() + "n"); } } 28. ADO.NET: Data Provider, Exceptionpublic static int Main(string[] args) {try Gestione{ delleSqlConnection conn = new SqlConnection(ConnectionString); eccezioni// Associo un event handler allevento di InfoMessageconn.InfoMessage += new SqlInfoMessageEventHandler(myHandler);conn.Open();} catch (SqlException e) {for (int i=0; i < e.Errors.Count; i++){ Console.WriteLine("Index #" + i + "n Error: " + e.Errors[i].ToString() + "n");}catch (Exception e){ Console.WriteLine(e.Message);}finally{ conn.Close(); } return 0;} 29. ADO.NET: Data Set Fin qui si potrebbe obiettare che tutto sommato le cose sono come in ADO, fatta eccezione per denominazione diversa di oggetti e metodi e la gestione delle eccezioni. Vero, ma ora parliamo dei Data Set che sono il fulcro del disconnected work. 30. ADO.NET: Data SetPermette di gestire i dati come se si disponesse di database relazionaleimmagazzinato nella memoria del processo.Le caratteristiche salienti di un Data Set sono: Residente in memoria di lavoro; Disconnesso dalla sorgente dati esterna; Permette di specificare vincoli e relazioni tra i dati contenuti; E accessibile in scrittura; Permette di propagare le modifiche alla sorgente dati; Supporta nativamente la (de)serializzazione in formato XML E un contenitore di vari tipi di oggetti (in particolare tabelle e relative relazioni): o DataTable rappresenta una tabella o DataColumn rappresenta una colonna di una tabella o DataRow rappresenta una riga di una tabella o Constraint rappresenta un vincolo di integrit su una tabella o DataRelation rappresenta una relazione tra due tabelle 31. ADO.NET: Data Set Object Model CollezioniDataSet DataSetDataRelationsCollectionDataTableCollection DataRelation DataTable DataTableDataTable ConstraintCollection DataRowCollection DataColumnCollectionDataColumnDataRow Constraint DataRow DataColumn 32. ADO.NET: Ruolo del DataAdapter SelectxxxCommandxxxCommandBuilder xxxDataAdapter InsertxxxCommandxxxConnection UpdatexxxCommand DeletexxxCommandDataDataSet 33. ADO.NET: Architettura del DataAdapter XxxDataAdapterSelectCommandUpdateCommand InsertCommand DeleteCommand XxxDataReader XxxCommand XxxCommand XxxCommand XxxCommand XxxConnection sp_SELECT sp_UPDATE sp_INSERT sp_DELETE 34. ADO.NET: Popolare un Data SetEssendo un Data Set una sorta di mini-db relazionale in memoria possibilepopolarlo si accedendo ad una sorgente dati come un RDBMS: Dim adaptSQL As New SqlClient.SqlDataAdapter(Select * from authors", conSQL) Dim datPubs As DataSet = New DataSet( ) adaptSQL.Fill(datPubs, "NewTable")ma anche creandolo per via programmatica Dim datPubs As New DataSet( ) Dim tblAuthors As DataTable = New DataTable("authors") tblAuthors.Columns.Add("AuthorID", System.Type.GetType("System.Int32"))Nel primo caso (quello pi consueto) spicca la creazione della classeSqlDataAdapter che il vero nodo di collegamento tra il mondo connesso equello disconnesso. Infatti il DataSet viene riempito dai dati e si pu lavorarein modalit disconessa.Terminate le attivit di modifica possibile aggiornare la sorgente dati originale: adaptSQL.Update (datPubs, "miaTabella") 35. ADO.NET: la propriet DataRowSetOgni riga inserita nella rispettiva tabella ha uno stato contenuto della proprietRowState del DataRow. In pratica una riga modifica il proprio stato dopo ognimodifica.I valori che il RowState pu assumere sono contenuti nellenumeratoreDataRowState: Valore Descrizione AddedLa riga stata aggiunta alla tabella DeletedLa riga contrassegnata per leliminazione della tabella Detached La riga stata creata ma non ancora aggiunta alla tabella o stata eliminata dalla collection delle righe Modified Alcune colonne della riga sono state modificate UnchangedNessuna modifca stata eseguita dallultima invocazione aAcceptChanges. E anche lo stato di tutte le righe quando latabella viene creataII metodo AcceptChanges conferma le modifiche e porta lo stato in unchanged.Lo stesso vale per la RejectChanges che per annulla le modifiche 36. ADO.NET: Data Set multi TabellaCome esposto la potenza di un DataSet quello di contenere pi tabelle e lerelative relazioni.Vediamo come inserire pi tabelle in un DataSet grazie al metodo FILL():Dim mySqlDataAdapter As New SqlDataAdapter("select * from customers", mySqlConnection)Dim myDataSet As New DataSet()mySqlDataAdapter.Fill(myDataSet, "Customers")Tabella CustomersmySqlDataAdapter.SelectCommand.CommandText = "select * from orders"mySqlDataAdapter.Fill(myDataSet,"Orders")Tabella OrdersDataSet:Customers OrdersData Tables 37. ADO.NET: Data Set, classe DataTableOgni elemento della propriet Tables unistanza della classe DataTableUn oggetto DataTable espone le propriet: Columns: una collezione di istanze di DataColumn Rows: una collezione di istanze della classe DataRow Una istanza della classe DataRow: mette a disposizione il contenuto delleproprie colonne mediante la propriet Item Vediamo un utilizzo di tali propriet:Dim numeroRighe As Int32 = unaTabella.Rows.CountDim indiceRiga As Int32Dim unaRiga As DataRowFor indiceRiga = 0 To numeroRighe - 1unaRiga = unaTabella.Rows(indiceRiga)Dim nomeAutore As String = _unaRiga.Item("au_fname").ToString()Next 38. ADO.NET: Data Set, classe DataRelationOltre alla propriet tables, fondamentale Relations, una collezione di istanzedella classe DataRelation.Un oggetto DataRelation espone le propriet: definisce una associazione tra le colonne di differenti DataTable; definisce una associazione orientata alla navigazione sui dati; NON costituisce una constraint; Vediamo un utilizzo di tali propriet patendo dalla loro creazione: Dim relPubsTitle As New DataRelation("PubsTitles", _datPubs.Tables("Publishers").Columns("pub_id"), _datPubs.Tables("Titles").Columns("pub_id")) datPubs.Relations.Add(relPubsTitle)Accedere ai dati associati Dim PubRow, TitleRow As DataRow, TitleRows( ) As DataRow PubRow = datPubs.Tables("Publishers").Rows(0) TitleRows = PubRow.GetChildRows("PubsTitles") 39. ADO.NET: Data Set, usare Constraint Il supporto alle constraint della classe DataSet permette di: Creare constraint attraverso le classi ForeignKeyConstraints e UniqueConstraints Usare le constraint esistenti nel DB adaptSQL = New SqlClient.SqlDataAdapter("Select title_id title, type, price from titles", conSQL) adaptSQL.FillSchema(datPubs, schematype.Source, "Titles") adaptSQL.Fill(datPubs, "Titles") Operazioni sui dati adaptSQL.Fill(datPubs, "Titles") Una constraint ForeignKeyConstraint: permette lintegrit referenziale se la propriet EnforceConstraints del DataSet impostata a True Determina le azioni effettuate nelle tabelle correlate, attraverso le propriet DeleteRule e UpdateRule Azione Descrizione Cascade Cancella o aggiorna le righe correlate. E il default. SetNull Imposta a DBNull il valore delle righe correlate. SetDefaultImposta al DefaultValue il valore delle righe correlate. NoneNessuna azione/modifica, viene sollevata una eccezione. 40. ADO.NET: Data Set, modificare i dati Vediamo come elaborare i dati attraverso i DataSet. Aggiungere Righe Dim drNewRow As DataRow = datPubs.Tables("Titles").NewRow Popolare le colonne datPubs.Tables("Titles").Rows.Add(drNewRow) Modificare Righe drChangeRow.BeginEdit( ) drChangeRow("Title") = drChangeRow("Title").ToString & " 1" drChangeRow.EndEdit( ) Cancellare Righe datPubs.Tables("Titles").Rows.Remove(drDelRow) 41. ADO.NET: Data Set, aggiornare la sorgente dati Possiamo ripercuotere le modifiche effettuate al DataSet sul DB: Esplicitando il comando di aggiornamento Dim comm As New SqlClient.SqlCommand("Insert titles" & _ "(title_id, title, type) values(@t_id,@title,@type)") comm.Parameters.Add("@t_id",SqlDbType.VarChar,6,"title_id") comm.Parameters.Add("@title",SqlDbType.VarChar,80,"title") comm.Parameters.Add("@type",SqlDbType.Char,12,"type") adaptSQL.InsertCommand = comm adaptSQL.Update(datPubs, "titles")Generando automaticamente il comando di update Dim sqlCommBuild As New SqlCommandBuilder(adaptSQL) MsgBox(sqlCommBuild.GetInsertCommand.CommandText) adaptSQL.Update(datPubs, "titles") 42. Microsoft: ADO.NET 1.x to 2.0ActiveX Data Object .NET dalla versione 1.x alla 2.0 43. ADO.NET 2.0: evoluzione ADO.NET v1.0/1.1 basato su alcune interfacce comuni, implementate dai singoli provider. Nonostante la flessibilit che ci comporta problematico scrivere codice indipendente dalla base dati. ADO .NET 2.0 basato su classi base condivise dai provider, e si presenta come unestensione delle versioni precedenti non non introducendo alcuna incompatibilit. Lutilizzo di classi base condivise e non di interfacce permette di implementare unarchitettura basata sul pattern Factory. Resta comunque la presenza di una sintassi SQL specifica per la base dati;Architettura basata sul pattern Factory. 44. ADO.NET 2.0: Common Provider Model IDb* interfaces (es: IDbConnection) Layer Db* abstract base classes (es: DbConnection)Provider-IndependentDb*Base implementation classes3rd 3rdLayer Sql OleDbODBCOracle Party 1 Party 2 Provider-SpecificADO.NET 2 usa un set di classi base che espongono i metodi necessari a generare:Connection, Commands, Parameters, ecc.In pratica viene inserito un nuovo layer (provider indipendent) che va a posizionarsi tra leclassiche interfacce IDB* e la relativa implementazione specifica. Il motivo dellintroduzione ditale layer (e delle relative classi base) sar chiaro a breve.E utile precisare che lo sviluppatore pu continuare ad usare, se lo desidera, le vecchie tecnicheesistenti nelle precedenti versioni senza alcuna modifica. 45. ADO.NET 2.0: Classi Provider IndipendentLe nuove classi base sono definite nel namespace System.Data.CommamdDi seguito elenchiamo le pi comuni: DbCommand DbCommandBuilderDbConnection DataAdapter DbDataAdapter DbDataReader DbParameter DbParameterCollection DbTransaction DbProviderFactory DbProviderFactories DbException 46. ADO.NET 2.0: insieme dei componenti DataSource TableAdapter TableAdapter TableAdapterDataTableDataTableDataTable DataSetBindingSource BindingSource BindingSource NamedRange ListObject Label Bookmark TextBox Label 47. ADO.NET 2.0: il Pattern FactoryIl Pattern Factory (classificato come Creational Pattern) ha lo scopo di creare facilmentenuovi oggetti, in dipendenza degli eventuali parametri passati al metodo di creazione.Creazione normale di un oggetto:Creazione con il Factory Class1 myClass = new Class1() Class1 myClass = Factory.create() 48. ADO.NET 2.0: il Pattern Factory in Ado.net 2 Il Ado.Net 2 il pattern Factory implementato nel namespaceSystem.Data.Common Come si usa:1. Importare il namespace System.Dta.Common2. Creare listanza del Factory:DbProviderFactory factory = DbProviderFactories.GetFactory("provider-name") 3. Creare le instanze degli oggetti: DbConnection con = factory.CreateConnection() DbCommand cmd = con.CreateCommand() Come si pu intuire la dinamicit sta nel parametro passato al metodo GetFactory. Infatti possible utilizzare variare la sorgente dati utilizza semplicemente variando il relativo parametro e lasciando tutti il resto del codice inalterato! 49. ADO.NET 2.0: Provider EnumeratorDove recuperiamo i nomi dei managed provider disponibili?Assodato che ogni provider ha un nome invarianteper esempio: "System.Data.SqlClient", "System.Data.OracleClient" possibile ottenerne la lista dei provider factory disponibili attraverso il metodo: GetFactoryClasses() il quale ritorna un oggetto di tipo DataTable.DataTable dt = DbProviderFactories.GetFactoryClasses()DbProviderFactory factory = DbProviderFactories.GetFactory(dt.Rows[x])... o ...DbProviderFactory factory = DbProviderFactories.GetFactory(dt.Select("InvariantName=System.Data.SqlClient")[0]["InvariantName"].ToString()); 50. ADO.NET 2.0: Performance ImprovementsNella versione 1.x Ado.Net offriva ottime performance per linserimento di datiallinterno dei DataSet, ma gli aggiornamenti soffrivano del numero di righe presential suo interno.La versione 2.0 introduce una indicizzazione interna delle righe per ottimizzare leprestazioni. Infatti i tempi di: Insert e Delete crescono logaritmicamente (tempi necessari allaggiornamento degli indici);Update rimangono quasi costanti (grazie allaccesso delle righe tramite gliindici)Con la versione 2.0 fa la comparsa anche la Serializzazione binaria dei DataSet.Infatti i DataSet v1.x erano sempre serializzati in XML, vantaggioso per lo scambiodati, ma penalizzante per le performance.La v2.0 supporta la serializzazione binaria che pi veloce ed occupa meno spazioa scapito ovviamente dellinteroperabilit. Per ottenere tale serializzazione bastaimpostare la propriet RemotingFormat del DataSet DataSet.RemotingFormat = SerializationFormat.Binary 51. ADO.NET 2.0: Popolare un Data Set (1)Esistono varie modalit per popolare un Data Set: da un datasource (DataSet o DataTable), utilizzando il DataAdapter ed ilmetodo Fill:DataAdapter.Fill(DataSet, "table-name") con la versione 2 questo metodo ha guadagnato due nuove propriet: DataAdapter.FillLoadOption AcceptChangesDuringUpdate effettuando il Merge delle righe da un altro DataSet attraverso il metodoMerge caricando i dati attraverso un DataReader tramite il nuovo metodoDataSet.Load:Load(DataReader [, load-option] [, tables-array]) utilizzando lenumeratore LoadOption: PreserveCurrentValues UpdateCurrentValues OverwriteRow 52. ADO.NET 2.0: Popolare un Data Set (2)Compariamo le tre tecniche viste nella slide precedente: DataAdapter.Fill(): popola il DataSet con una tabella alla volta. Dopo linserimento diogni riga viene invocato automaticamente lAcceptChanges; se si desidera modificare talecomportament bisogna settare la propriet AcceptChangesDuringFill.Il metodo Fill() pu anche essere utilizzato per effettuare il refresh delle tuple: infatti se sicaricano righe con primary key gi presenti del DataSet, questultime verranno sostituite. DataSet.Merge(): permette combinare le righe di due DataSet diversi. Le righe delDataSet di lettura vengono inserite nelle tabelle (con lo steso nome) del primo,sostituendo eventualmente quelle con lo stesso primary key. Nel caso si voglia uncomportamento diverso bisogna settare il parametro PreserveChange. Al termine delleoperazioni lo stato delle righe Modified o Added. DataSet.Load(): il nuovo metodo introdotto con Ado.Net 2. Attraverso un DataReader possibile utilizzare una query che ritorna pi tabelle che vengono inserite nel DataSetusando il nome specificato dal parametro table-array. Per catturare eventuali errori possibile specificare un delegato che effettui le opportune operazioni.Sia il metodo Fill() che il metodo Load() traggono vantaggio dal nuovo enumeratoreLoadOption. Nel caso di Fill() utilizzato settando il parametro FillLoadOption delDataAdapter, mentre nel caso di Load() come parametro. In pratica grazie a LoadOption possibile controllare il modo in cui le righe vengono unite (merge) tra loro. 53. ADO.NET 2.0: Popolare un Data Set (3)RowState of PreserveCurrentValues UpdateCurrentValues OverwriteRowExisting Row(the default value)Added Current = ExistingCurrent = IncomingCurrent = IncomingOriginal = Incoming Original = Existing Original = IncomingRowState = Modified RowState = AddedRowState = UnchangedModifiedCurrent = ExistingCurrent = IncomingCurrent = IncomingOriginal = Incoming Original = Existing Original = IncomingRowState = Modified RowState = Modified RowState = UnchangedDeleted Current = Existing* Undo Delete * Undo DeleteOriginal = Incoming Current = IncomingCurrent = IncomingRowState = DeletedOriginal = Existing Original = IncomingRowState = Modified RowState = UnchangedUnchanged Current = IncomingCurrent = IncomingCurrent = IncomingOriginal = Incoming Original = Existing Original = IncomingRowState = Unchanged* if new value = existing RowState = Unchangedvalue:RowState = Unchanged* else:RowState = ModifiedNo matching Current = IncomingCurrent = IncomingCurrent = Incomingexisting row in Original = Incoming Original = Existing Original = Incomingthe table RowState = UnchangedRowState = AddedRowState = Unchanged 54. ADO.NET 2.0: Altre nuove feauturesAdo.Net 1.x non prevedeva la possibilit di settare manualmente lo stato delle righe:lo stato era aggiornato automaticamente in base alle operazione effettuate. Questopoteva rendere difficile laggiornamento di specifiche righe perch lUpdate non eracondizionabile.Ado.Net 2 introduce due metodi relativi ai DataRow:DataRow.SetAddedDataRow.SetModifiedproprio per variarne lo stato.Ado.Net 2 introduce inoltre la classe DataTableReader in grado di convertire i daticontenuti in un DataSet in uno stream, utile per passare un DataSet ad una claseche accetta un DataReaeder. Va evidenziato che possibile specificare quali tabelleesportare.Per ottenere un DataTableReadere possibile invocare DataSet.GetDataReader(). 55. ADO.NET 2.0: Altre nuove feauturesAdo.Net 2 ha reso indipendente il DataTable. Praticamente possibile effettuare con essotutte le operazioni previste per il DataSet:ReadXml, ReadXmlSchema, WriteXml, WriteXmlSchema, Clear, Clone, Copy, Merge,GetChangessupportando direttamente la serializzazione (implementando linterfaccia IXmlSerializable) epermettendo quindi di restituirne unistanza mediante WebServices o Remoting.Capite bene che inviare su rete un singolo DataTable molto pi conveniente che un interoDataSet!Ovviamente per essere totalmente indipendente deve essere possibile popolare direttamenteun DataTable. Ecco quindi il motivo dellimplementazione dei metodi del DataAdapter chesupportino direttamente un DataTable:DataAdapter.Fill(DataTable)DataAdapter.Fill(DataTable[ ], )DataAdapter.Update(DataTable)e dei metodi propri del DataTable: DataTable.Load(DataReader [, load-option] [, FillErrorEventHandler]) DataTable.GetDataReader, ottiene uno stream da una DataTable 56. ADO.NET 2.0: Comandi AsincroniADO.NET 2 introduce il modello di esecuzione asincrona (similare allAPM delframework .net 2) che riduce i tempi di latenza delle web/windows aplpicationdurante le operazioni sui dati, permettendo lesecuzione concorrente di moltepliciquery.Seguendo proprio lAPM Model i metodi sono del tipo: BeginXXX ed EndXXX, adesempio: BeginExecuteReader e EndExecuteReader; BeginExecuteNonQuery e EndExecuteNonQuerycos possibile utilizzare le tecniche di Polling, Wait e Callback per eseguireoperazioni in attesa del completamento del metodo BeginXXX.Per poter utilizzare il modello asincrono bisogna aggiungere "async=true" allaConnection String ed evitare di utilzzare i Multiple Active Results Sets (di cuiparleremo dopo). 57. ADO.NET 2.0: Esecuzione AsincronaApplicationRowset 1 Data 1 Data 1 Data 1 Data 1 Data 1 Data 1Data 1Data 1 Data 1 Data 1Data 1Data 1 Database1 Data 1 Data 1 Data 1Data 1Data 1Data 1 Data 1 Data 1 Data 1Data 1Data 1Data 1 ConnectionLatency 3 secs Data 1 Data 1 Data 1 Data 1 Rowset 2 Data 1 Data 1 Data 1 Data 1 Data 1 Data 1Data 1Data 1 Data 1 Data 1Data 1Data 1Database2 Data 1 Data 1 Data 1Data 1Data 1Data 1 Data 1 Data 1 Data 1Data 1Data 1Data 1 ConnectionLatency 8 secs Data 1 Data 1 Data 1 Data 1 Rowset 3 Data 1 Data 1 Data 1 Data 1 Data 1 Data 1 Data 1Data 1Data 1Data 1 Data 1 Data 1 Data 1Data 1Data 1Data 1Database3 Data 1 Data 1Data 1Data 1 Data 1 Data 1Data 1Data 1 ConnectionLatency 5 secs Data 1 Data 1 Data 1 Data 1Tempo per visualizzare i dati: ~ 3 secs 16 11 secsNel caso di esecuzione sincrona, ogni connection deve attendere il termine dellaprecedente per poter ritornare i dati e quindi per permette allapplicazione divisualizzarli.Risultato: il tempo totale la somma (teorica) dei tempi necessari alle tre connection 58. ADO.NET 2.0: Esecuzione Asincrona ApplicationRowset 1 Data 1 Data 1Data 1Data 1 Data 1 Data 1Data 1Data 1 Database1 Data 1 Data 1 Data 1Data 1Data 1Data 1 Data 1 Data 1 Data 1Data 1Data 1Data 1 Connection1 Latency 3 secs Data 1 Data 1 Data 1 Data 1 Data 1 Data 1 Data 1 Data 1Rowset 2 Data 1 Data 1Data 1Data 1 Data 1 Data 1Data 1Data 1Database2 Data 1 Data 1 Data 1Data 1Data 1Data 1 Data 1 Data 1 Data 1Data 1Data 1Data 1 Connection2 Latency 8 secs Data 1 Data 1 Data 1 Data 1 Data 1 Data 1 Data 1 Data 1Rowset 3 Data 1 Data 1Data 1Data 1 Data 1 Data 1Data 1Data 1Database3 Data 1 Data 1Data 1Data 1 Data 1 Data 1Data 1Data 1 Connection3 Data 1 Data 1Data 1Data 1 Data 1 Data 1Data 1Data 1 Latency 5 secs Data 1 Data 1 Data 1 Data 1~ 8 secsNel caso di esecuzione asincrona, le connection vengono avviatecontemporaneamente e ritorna appena terminano la propria attivit, indipendementedalle altre (nellesempio la terza connection ritorna dopo 5sec invece che dei 16precedenti).Risultato: il tempo totale pari al tempo della connection pi lenta. 59. ADO.NET 2.0: Design Approaches (1)In attesa del completamento di un comando di BeginXXX possiamo effettuare altreoperazioni utilizzando tre tecniche: Polling, Wait (All & Any) e Callback.Polling Model Avviare il comando asincrono: Dim result As IAsyncResult = MyCommand.BeginExecuteReader()Aspettare fino al termine dellescuzione: While Not result.IsCompleted Codice da eseguire End WhileRecupera i Risultati Dim reader As SqlDataReader = MyCommand.EndExecuteReader(result ) nel caso di query che non ritorna un rowset (BeginExecuteNonQuery, BeginExecuteScalar, etc.) possibile ottenere il numero di righe interessate dalloperazione o un singolo valore. 60. ADO.NET 2.0: Design Approaches (2)Wait (All) Model Avviare uno o pi comandi asincroni: Dim resultx As IAsyncResult = MyCommand.BeginExecuteReader() Attendere il completamento di tutti i comandi WaitHandle.WaitAll(New WaitHandle(){result1.AsyncWaitHandle,result2.AsyncWaitHandle,result3.AsyncWaitHandle}, timeout - ms, True)Recupera i Risultati Dim reader As SqlDataReader = MyCommand.EndExecuteReader(resultx)Questo modello ideale per le applicazioni ASP.NET (dove necessario avere tutti idati prima di poter fare qualcosa) ed analogomante per generare loutput da un WebServices. 61. ADO.NET 2.0: Design Approaches (3)Wait (Any) Model Avviare uno o pi comandi asincroni come array di istanze di IAsyncResult:Dim resultx As IAsyncResult = MyCommand.BeginExecuteReader() Attendere il completamento di ogni comando i comandiDim i As IntegerFor i = 0 To result_array.Lengthindex = WaitHandle.WaitAny(result_array, timeout, true)Select Case index Case 0 Dim reader As SqlDataReader = MyCommand.EndExecuteReader(resultx).... End SelectEnd For per catturare eventuali timeout, il Case deve contenere una clausolacase WaitHandle.WaitTimeoutQuesto modello ideale per le Windows Application perch permette di visualizzare(utilizzare) i dati appena diventano disponibili senza aspettare il risultato di tutte lequery. Inoltre grazie al metodo Load del DataSet possibile usare immediatamenteogni singolo dataReader per caricare una tabella nel DataSet stesso. 62. ADO.NET 2.0: Design Approaches (4)Callback Model Avviare lesecuzione, specificando la funzione di callback (delegato) ed ilCommand come AsyncState: MyCommand.BeginExecuteReader(new AsyncCallback(MyCallback), cmd) Creare il gestore di callback Sub MyCallback(ByVal result As IAsyncResult) Dim cmd As SqlCommand = DirectCast(result.AsyncState, SqlCommand) Dim reader As SqlDataReader = cmd.EndExecuteReader(result) End SubSi tratta probabilmente dellapproccio migliore perch lascia al runtime la gestionecompleta della chiamata asincrona e lincovazione auomatica di un metodo cheesegua le opportune operazioni su dati ottenuti.Il tutto mentre lapplicativo continua la sua normale esecuzione. 63. ADO.NET 2.0: Design Approaches (5)Per ognuno degli approcci presentati bisogna applicare una gestione apposita delleEccezioni e dei TimeOut.Per il WaitOne e WaitAll preferibile usare sempre il try/catch per ogni metodoEndXXXPer il WaitAny il return value uguale al tempo di TimeOutPer il CallBack preferibile usare sempre il try/catch per ogni metodo EndXXX 64. ADO.NET 2.0: Multiple Active Results Sets (MARS) (1) (Ri)Conoscete questo messaggio? System.InvalidOperationException: There is already an open DataReader associated with this Connection which must be closed first.In ADO.NET 1.x provando ad aprire pi results set o effettuare pi updatequery su una Connection provoca la suddetta eccezione.In ADO.NET 2 (con le Connection relative a SQL Server 2005) possibile inveceaprire pi results set sulla stessa Connection ed eseguire comandi multipli dimodifica sui datiIn sintesi: Mantiene disponibile una connessione quando apriamo un SqlDataReader al fine di poter: Eseguire unaltra query per ottenere un DataReader/XmlReader Eseguire comandi DML Possono essere attivi differenti result set contemporaeamente alternare fetch ad ogni reader Alternare query che non restituiscono reader 65. ADO.NET 2.0: Multiple Active Results Sets (MARS) (2) Vediamo uno scenario tipo: Recuperare la lista dei clienti e scorrerla Per ogni cliente, recuperare la lista degli ordini Per ogni ordine, recuperarne il dettaglio Nella v.1.x di Ado.Net, per ottenere ci usando dei reader erano necessarie differenti connessioni Mediante MARS, sufficiente una sola connessione se: I dati risiedono nello stesso database Usiamo SQL Server 2005/MDAC9 E utile evidenziare che MARS solo una feuture che semplifica le attivit di sviluppo, occupandosi automaticamente di gestire aperture/connessione delle connection necessario. Quindi va usato con attenzione per evitare cali prestazionali della propria applicazione. 66. ADO.NET 2.0: Multiple Active Results Sets (MARS) (3) Vediamo un esempio:Dim parentReader As DataReader = Command1.ExecuteReader()While parentReader.Read()processa la tupla letta crea il childReaderCommand2.Parameters("@id").Value = parentReader("id")Dim childReader As DataReader = Command2.ExecuteReader() processa il nuovo childReaderchildReader.Close()End WhileparentReader.Close()Questo codice apre un DataReader (parentReder) e chiama ciclicamente la Read() finch ancora presente una tupla.Per ogni tupla setta un parametro su Command2 e recupera un nuovo DataReader(childReader) sempre sulla stessa connessione.Dopo aver effettuato le opportune operazioni il childReader viene chiuso e si prosegue con lariga successiva. 67. ADO.NET DatabindingADO.NET & Data Component 68. DataBinding.: Cos il Databinding? (1) Databinding letteralmente significa legame ed lattivit che permette di stabilire automaticamente lo scambio di valori tra controllo e una sorgente dati. Il databinding evita codice noioso e ripetitivo nel quale assegniamo i dati alcontrollo e successivamente li riassegnamo alla sorgente dati. Il binding con DataSource poveri implica luso di reflection e quindi impoverisce le performance. Se invece il DataSource implementa le interfacce giuste il discorso molto diverso. 69. DataBinding: Cos il Databinding? (2) In ADO.NET le sorgenti dati disconnesse non hanno pi il concetto di record corrente. Il binding di dotnet gestito da un intermediario tra controllo e sorgente dati che implementa la classe base BindigManagerBase. La presenza di un unico intermediario per bindare pi controlli garantisce il sync tra questi. Ovviamente se non si desidera una sincronizzazione tra i controllo, basta creare pi binder. Sync BindingMan Data agerBase BindingManagerBase Sync Data BindingManagerBase 70. DataBinding:Il Binding Manager Il Binding Manager lintermediario ed univoco per ogni datasource. Per ogni binding manager ci sono uno o pi controlli, permettendo cos, eventualmente, di sincronizzarli durante la navigazione dei dati. Come detto, la classe base del binding manager BindingManagerBase (astratta) e ha due classi derivate: PropertyManager gestisce il binding con singoli elementi CurrencyManager gestisce il binding con liste di elementi 71. DataBinding: BindingContex Il BindingContext il contesto di binding, ovvero una lista di BindingManagerBase mantenuta tramite Hashtable. Poich il nome del datasource parte della chiave della Hashtable, non pi di un BindingManagerBase con lo stesso datasource pu esistere in un BindingContext Perci per non avere sync tra due controlli, i due BindingManagerBase devono appartenere a due BindingContext diversi BindingContext (Hashtable)BindingManagerBaseSyncDataBindingManagerBase BindingContext (Hashtable) 72. DataBinding: Simple & Complex Databinding (1) Possiamo avere due forme di DataBindig: Simple & Complex. Un databindind Simple quando s associa un singolo campo informazione (field) ad una singola propriet di un componente. Ad esempio la propriet Text della TextBox associato ad un campo di un db. Nel caso di binding pi elaborato, come pu essere il collegamento ad un DataGridView, si parla invece di ComplexBindig ed richiesto un supporto ad- hoc da parte del controllo. 73. DataBinding: Simple & Complex Databinding (2) CurrencyManagerBindingContextoppure PropertyManagerBindingManagerBaseBindingManagerBaseDataSource Data Simple BindingDataMember Bindings BindingControlBindingsCollection BindingoppurePropertyName ControlBindingsCollection BindingBindingContextComplex BindingBindingManagerBase DataDataSource Simple BindingDataMember BindingControlPropertyName 74. DataBinding: Simple Binding Come detto il SimpleBinding associa un qualsiasi tipo ad un controllo in modo da semplificare la presentazione di un valore e poterlo aggiornareProprietDataMembercontrollo DataSource int i=5; myLabel.DataBindings.Add("Text", i, null); se null viene usato ToString() Il binding con un singolo elemento implica luso di PropertyManager La propriet Position sar sempre 0 Il binding con una lista di elementi implica luso di CurrencyManager che ha il concetto di record corrente. Si usa Position per navigare le righe mostrate Non si usa Position per leggere la posizione perch la lista potrebbe contenere elementi che non vengono mostrati (es. filtro sulla dataview) Si usa Current per leggere lelemento nella lista sottostante (datasource) 75. DataBinding: Simple Binding, format and parseLa classe binding (disponibile solo nel simple binding) offre due eventiimportanti: format. Intercetta il dato proveniente dal DataSource prima che vengaimpostato nel controllo. parse. Intercetta il dato che dal controllo sta per essere trasferito alDataSourceCatturare e gestire questi eventi permette dimigliorare la qualit dellavisualizzazione dei dati secondo le proprie necessit.Non utile alla validazione che deve essere effettuata dagli appositi validation-control. 76. DataBinding: Complex Bindig Il ComplexBindig permette (attraverso gli oggetti ADO.NET) di creare rappresentazione complesse dei dati ed operare con essi.DataSourceDataMember IList IListSource.GetList() DataSet {return this.DefaultView; } DataTableDataView DataRow DataRowView DataRow DataRowView DataRow DataRowView 77. DataBinding: Complex Bindig (2) Per connettere un datasource ad un componente evoluto, si deve: 1. settare la propriet Component.DataSource = myDataSet 2. settare la propriet Component.DataMember = myTable.myColumn E buona norma non specificare mai nel DataSource myDataSet.myTable perch:il nome del DataSource funge da Key in BindingContextil designer usa la convenzione in alto Quando si usa il CurrencyManager, pu essere necessario usare il suo metodo Refresh affinch il controllo vengaaggiornato. La Listbox ha bisogno di questo refresh mentre altri controlli no. Affinch il DataSource sia sicuramente aggiornato necessario chiamare EndCurrentEdit 78. DataBinding: Non solo database Non detto che si debbano collegare i componenti solo ed esclusivamente ad un DataSet. Posso infatti creare anche creare una comune collection (list, arraylist, ecc) e collegarla come sorgente dati System.Collections.Arraylist list = new System.Collections.Arraylist(); list.add(new item(Woot)); list.add(new item(Funky)); list.add(new item(EarthCrack)); _randomListbox.DataSource = list; _randomListbox.DisplayValue = SmackTalk; 79. ADO.NET: ConclusioniADO.NET 2 un framework complesso che permette di lavorare in modoefficiente ed efficace con la grande maggioranza delle fonti dati oggidisponibili.Linfrastruttura permette agli Sviluppatori di concentrasi sulle questioni dibusiness evitando di scrivere codice ridondante e perdere intere giornate inattivit di debugging.