370 likes | 472 Views
ADO .NET 2.0: what’s new. Andrea Saltarello Software Architect – Managed Designs S.r.l. http://blogs.ugidotnet.org/pape. Sponsor. Parliamo di…. Architettura ADO .NET 2.0 System.Data: what’s new SqlClient enhancements M.A.R.S. Inizialmente annunciato come parte di ADO .NET 2.0…
E N D
ADO .NET 2.0: what’s new Andrea Saltarello Software Architect – Managed Designs S.r.l. http://blogs.ugidotnet.org/pape
Parliamo di… • Architettura ADO .NET 2.0 • System.Data: what’s new • SqlClient enhancements • M.A.R.S.
Inizialmente annunciato come parte di ADO .NET 2.0… E’ stato poi “agganciato” al rilascio di WinFS (Longhorn)… Ma WinFS è stato “tagliato” da Longhorn e posticipato a data da definirsi… Insomma… non ne parliamo ObjectSpaces Agenda – Non parliamo di…
Prerequisiti per ADO .NET 2.0 • Non necessitano di MDAC: • Classi base, comuni (System.Data.Common) e disconnesse • .NET managed provider per SQL Server e Oracle • Usano MDAC, senza particolari requisiti: • Managed provider OLEDB e ODBC • Vanno bene le versioni 2.6, 2.7, 2.8 o… 9.0
Common Provider Model • ADO.NET v1.0/1.1 è basato su alcune interfacce • E’ problematico scrivere codice indipendente dalla base dati • ADO .NET 2.0 è basato su classi base condivise dai provider • E’ una estensione, non introduce incompatibilità • La sintassi SQL è comunque specifica per la base dati! • Architettura basata sul pattern Factory
ADO .NET 2: Architettura IDb* interfaces (es: IDbConnection) Layer Provider-Independent Db* abstract base classes (es: DbConnection) Db*Base implementation classes Sql OleDb ODBC Oracle 3rd Party 1 3rd Party 2 Layer Provider-specific
Classi Provider-independent Sono definite nel namespace System.Data.Common • ad esempio:
Usare una Provider Factory • Importare il Namespace: using System.Data.Common • Creare l’istanza della Factory: static DbProviderFactory factory = DbProviderFactories.GetFactory("provider-name") • Creare le istanze degli oggetti: DbConnection con = factory.CreateConnection() DbCommand cmd = con.CreateCommand()
Provider Enumeration • Ogni provider ha un nome invariante • Per esempio: "System.Data.SqlClient", "System.Data.OracleClient" • Ottenere la lista delle provider factory installate 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());
Provider Enumeration usando una Provider Factory
Performance Improvements • Indicizzazione interna delle righe. I tempi di: • Insert e delete crescono logaritmicamente • update rimangono quasi costanti • Serializzazione binaria • I DataSet v1.x erano sempre serializzati in XML • Vantaggioso per lo scambio dati, ma penalizzante per le performance • La v2.0 supporta la serializzazione binaria • È più veloce ed occupa meno spazio • Basta usare: DataSet.RemotingFormat = SerializationFormat.Binary
Binary vs. XML Serialization Incrementi fino ad 80 x
Popolare un DataSet • DataAdapter.Fill(DataSet, "table-name") • Nuovo: proprietà DataAdapter.FillLoadOption e AcceptChangesDuringUpdate • Nuovo: metodo DataSet.Load • Load(DataReader [, load-option] [, tables-array]) • Nuovo: LoadOption enumeration • PreserveCurrentValues | UpdateCurrentValues | OverwriteRow
Nuove feature • RowState modificabile • Nuovi metodi: DataRow.SetAdded e DataRow.SetModified • Metodo DataSet.GetDataReader • Restituisce un DataTableReader • E’ possibile specificare quali tabelle includere
Popolare un DataSet con un DataReader e usare un DataTableReader.
DataTable “stand-alone” • Operazioni tipiche del DataSet supportate anche per le DataTable: • ReadXml, ReadXmlSchema, WriteXml, WriteXmlSchema, Clear, Clone, Copy, Merge, GetChanges • La classe DataTable ora supporta la serializzazione: • Perchè implementa IXmlSerializable • E’ possibile restituire una istanza di DataTable mediante Web Service o Remoting
Popolare ed usare DataTable • DataAdapter.Fill(DataTable) • DataAdapter.Fill(DataTable[ ], …) • Permette di selezionare un sottoinsieme di righe • DataAdapter.Update(DataTable) • DataTable.Load(DataReader [, load-option] [, FillErrorEventHandler]) • Nuovi metodi: BeginLoadData, Load, EndLoadData • DataTable.GetDataReader method • Ottiene uno stream da una DataTable
Update Batch • In 1.1, gli update dei DataSet sono eseguiti riga per riga • Il batch update riduce round-trip lungo la rete • DataAdapter.UpdateBatchSize = batch_size • Funziona all’interno di transazioni • Funziona con SQL Server 7.0, 2000, 2005 • Disponibile anche per il provider OracleClient
Comandi asincroni • Ideali per eseguire molteplici query • Il “solito” Async Pattern: Beginxxx e Endxxx • Supporta Polling, Wait e Callback • Non dovrebbe essere usato in abbinamento a MARS • usate una connessione per ogni Command • Aggiungere "async=true" alla connection string
Data 1 Data 1 Data 1 Data 1 Data 1 Data 1 Data 1 Data 1 Data 1 Data 1 Data 1 Data 1 Data 1 Data 1 Data 1 Data 1 Data 1 Data 1 Data 1 Data 1 Data 1 Data 1 Data 1 Data 1 Data 1 Data 1 Data 1 Data 1 Data 1 Data 1 Data 1 Data 1 Data 1 Data 1 Data 1 Data 1 Data 1 Data 1 Data 1 Data 1 Data 1 Data 1 Data 1 Data 1 Data 1 Data 1 Data 1 Data 1 Data 1 Data 1 Data 1 Data 1 Data 1 Data 1 Data 1 Data 1 Data 1 Data 1 Data 1 Data 1 Data 1 Data 1 Data 1 Data 1 Data 1 Data 1 Data 1 Data 1 Data 1 Data 1 Data 1 Data 1 Data 1 Data 1 Data 1 Data 1 Data 1 Data 1 Data 1 Data 1 Data 1 Data 1 Data 1 Data 1 Esecuzione sincrona Application Rowset 1 Database1 Latency 3 secs Connection Rowset 2 Database2 Latency 8 secs Connection Rowset 3 Database3 Latency 5 secs Connection Tempo per visualizzare i dati: ~ 16 secs ~ 11 secs ~ 3 secs
Data 1 Data 1 Data 1 Data 1 Data 1 Data 1 Data 1 Data 1 Data 1 Data 1 Data 1 Data 1 Data 1 Data 1 Data 1 Data 1 Data 1 Data 1 Data 1 Data 1 Data 1 Data 1 Data 1 Data 1 Data 1 Data 1 Data 1 Data 1 Data 1 Data 1 Data 1 Data 1 Data 1 Data 1 Data 1 Data 1 Data 1 Data 1 Data 1 Data 1 Data 1 Data 1 Data 1 Data 1 Data 1 Data 1 Data 1 Data 1 Data 1 Data 1 Data 1 Data 1 Data 1 Data 1 Data 1 Data 1 Data 1 Data 1 Data 1 Data 1 Data 1 Data 1 Data 1 Data 1 Data 1 Data 1 Data 1 Data 1 Data 1 Data 1 Data 1 Data 1 Data 1 Data 1 Data 1 Data 1 Data 1 Data 1 Data 1 Data 1 Data 1 Data 1 Data 1 Data 1 Connection1 Connection2 Connection3 Esecuzione asincrona Application Database1 Latency 3 secs Rowset 1 Database2 Latency 8 secs Rowset 2 Rowset 3 Database3 Latency 5 secs Tempo per visualizzare i dati: ~ 8 secs
Esecuzione asincrona: Polling Model • Avviare un comando asincrono: Dim result As IAsyncResult = MyCommand.BeginExecuteReader() • Aspettare fino al termine della esecuzione: While Not result.IsCompleted ‘Codice da eseguire End While • Recuperare i risultati: Dim reader As SqlDataReader = MyCommand.EndExecuteReader(result )
Esecuzione asincrona: 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) • Recuperare i risultati: Dim reader As SqlDataReader = MyCommand.EndExecuteReader(resultx) • Ideale per le Web Application ASP.NET
Esecuzione asincrona: 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: Dim i As Integer For i = 0 To result_array.Length index = WaitHandle.WaitAny(result_array, timeout, true) Select Case index Case 0 Dim reader As SqlDataReader = MyCommand.EndExecuteReader(resultx) ... End Select End For
Esecuzione asincrona: Callback Model • Avviare l’esecuzione, specificando la funzione di callback e il command come AsyncState: MyCommand.BeginExecuteReader(new AsyncCallback(MyCallback), cmd) • Creare il gestore del callback: Sub MyCallback(ByVal result As IAsyncResult) Dim cmd As SqlCommand = DirectCast(result.AsyncState, SqlCommand) Dim reader As SqlDataReader = cmd.EndExecuteReader(result) End Sub
DataReader: Paging • Il paging? C’est plus facile, col metodo ExecutePageReader • Accetta l’indice della prima riga e il numero di righe da restituire • Non garantisce consistenza • Senza il supporto di una transazione, alcune righe potrebbero essere saltate o ripetute • Moooolto più veloce che leggere tutte le righe ed ignorare quelle non desiderate • E’ comunque preferibile eseguire una query “mirata” Troppo bello per essere vero? Lo pensa anche Microsoft, infatti ha rimosso il metodo nella beta2
Multiple Active Result Sets (MARS) • (Ri)Conoscete questo messaggio? • System.InvalidOperationException: There is already an open DataReader associated with this Connection which must be closed first.
Multiple Active Results Sets (MARS) • Mantiene disponibile una connessione quando apriamo un SqlDataReader al fine di poter: • Eseguire un’altra 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
Alternare Results Set • Scenario tipico: • Recuperare la lista dei clienti e scorrerla • Per ogni cliente, recuperare la lista degli ordini • Per ogni ordine, recuperarne il dettaglio • Nella v1, 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
Interleaved Results Sets Example Dim parentReader As DataReader = Command1.ExecuteReader() While parentReader.Read() ' process parent row data here ' then get rowset from child table Command2.Parameters("@id").Value = parentReader("id") Dim childReader As DataReader = Command2.ExecuteReader() ' process child rows here childReader.Close() End While parentReader.Close()
Links http://www.ugidotnet.org http://forum.ugidotnet.org http://mobile.ugidotnet.org