ado .net 2.0: what’s new
DESCRIPTION
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… - PowerPoint PPT PresentationTRANSCRIPT
ADO .NET 2.0: what’s newADO .NET 2.0: what’s newADO .NET 2.0: what’s newADO .NET 2.0: what’s new
Andrea SaltarelloAndrea SaltarelloSoftware Architect – Software Architect – Managed Designs S.r.l.http://blogs.ugidotnet.org/pape
SponsorSponsor
Parliamo di…Parliamo di…Parliamo di…Parliamo di…
• Architettura ADO .NET 2.0Architettura ADO .NET 2.0
• System.Data: what’s newSystem.Data: what’s new
• SqlClient enhancementsSqlClient enhancements
• M.A.R.S.M.A.R.S.
• Architettura ADO .NET 2.0Architettura ADO .NET 2.0
• System.Data: what’s newSystem.Data: what’s new
• SqlClient enhancementsSqlClient enhancements
• M.A.R.S.M.A.R.S.
Agenda – Non parliamo di…Agenda – Non parliamo di…Agenda – Non parliamo di…Agenda – Non parliamo di…
• Inizialmente annunciato come parte di ADO .NET Inizialmente annunciato come parte di ADO .NET 2.0…2.0…
• E’ stato poi “agganciato” al rilascio di WinFS E’ stato poi “agganciato” al rilascio di WinFS (Longhorn)…(Longhorn)…
• Ma WinFS è stato “tagliato” da Longhorn e Ma WinFS è stato “tagliato” da Longhorn e posticipato a data da definirsi…posticipato a data da definirsi…
• Insomma… non ne parliamo Insomma… non ne parliamo
• Inizialmente annunciato come parte di ADO .NET Inizialmente annunciato come parte di ADO .NET 2.0…2.0…
• E’ stato poi “agganciato” al rilascio di WinFS E’ stato poi “agganciato” al rilascio di WinFS (Longhorn)…(Longhorn)…
• Ma WinFS è stato “tagliato” da Longhorn e Ma WinFS è stato “tagliato” da Longhorn e posticipato a data da definirsi…posticipato a data da definirsi…
• Insomma… non ne parliamo Insomma… non ne parliamo
ObjectSpacesObjectSpacesObjectSpacesObjectSpaces
Prerequisiti per ADO .NET Prerequisiti per ADO .NET 2.02.0
Prerequisiti per ADO .NET Prerequisiti per ADO .NET 2.02.0
• Non necessitano di MDAC:Non necessitano di MDAC:• Classi base, comuni (System.Data.Common) e Classi base, comuni (System.Data.Common) e
disconnessedisconnesse• .NET managed provider per SQL Server e Oracle.NET managed provider per SQL Server e Oracle
• Usano MDAC, senza particolari Usano MDAC, senza particolari requisiti:requisiti:• Managed provider OLEDB e ODBCManaged provider OLEDB e ODBC• Vanno bene le versioni 2.6, 2.7, 2.8 o… 9.0Vanno bene le versioni 2.6, 2.7, 2.8 o… 9.0
• Non necessitano di MDAC:Non necessitano di MDAC:• Classi base, comuni (System.Data.Common) e Classi base, comuni (System.Data.Common) e
disconnessedisconnesse• .NET managed provider per SQL Server e Oracle.NET managed provider per SQL Server e Oracle
• Usano MDAC, senza particolari Usano MDAC, senza particolari requisiti:requisiti:• Managed provider OLEDB e ODBCManaged provider OLEDB e ODBC• Vanno bene le versioni 2.6, 2.7, 2.8 o… 9.0Vanno bene le versioni 2.6, 2.7, 2.8 o… 9.0
Common Provider ModelCommon Provider ModelCommon Provider ModelCommon Provider Model
• ADO.NET v1.0/1.1 è basato su alcune ADO.NET v1.0/1.1 è basato su alcune interfacceinterfacce• E’ problematico scrivere codice indipendente dalla E’ problematico scrivere codice indipendente dalla
base datibase dati
• ADO .NET 2.0 è basato su classi base ADO .NET 2.0 è basato su classi base condivise dai providercondivise dai provider• E’ una estensione, non introduce incompatibilitàE’ una estensione, non introduce incompatibilità• La sintassi SQL è comunque La sintassi SQL è comunque specificaspecifica per la base dati! per la base dati!• Architettura basata sul pattern FactoryArchitettura basata sul pattern Factory
• ADO.NET v1.0/1.1 è basato su alcune ADO.NET v1.0/1.1 è basato su alcune interfacceinterfacce• E’ problematico scrivere codice indipendente dalla E’ problematico scrivere codice indipendente dalla
base datibase dati
• ADO .NET 2.0 è basato su classi base ADO .NET 2.0 è basato su classi base condivise dai providercondivise dai provider• E’ una estensione, non introduce incompatibilitàE’ una estensione, non introduce incompatibilità• La sintassi SQL è comunque La sintassi SQL è comunque specificaspecifica per la base dati! per la base dati!• Architettura basata sul pattern FactoryArchitettura basata sul pattern Factory
ADO .NET 2: ArchitetturaADO .NET 2: ArchitetturaADO .NET 2: ArchitetturaADO .NET 2: ArchitetturaIDb* interfaces (es: IDbConnection)IDb* interfaces (es: IDbConnection)
Db* abstract base classes (es: DbConnection)Db* abstract base classes (es: DbConnection)
Db*Base implementation classesDb*Base implementation classes
SqlSql OleDbOleDb ODBCODBC OracleOracle 33rdrd Party 1Party 1
33rdrd Party 2Party 2
Layer Provider-Independent
Layer Provider-specific
Classi Provider-independentClassi Provider-independentClassi Provider-independentClassi Provider-independent
Sono definite nel namespace System.Data.CommonSono definite nel namespace System.Data.Common– ad esempio:ad esempio:
Sono definite nel namespace System.Data.CommonSono definite nel namespace System.Data.Common– ad esempio:ad esempio:
DbCommandDbCommand DbCommandBuilderDbCommandBuilder DbConnectionDbConnection
DataAdapterDataAdapter DbDataAdapterDbDataAdapter DbDataReaderDbDataReader
DbParameterDbParameter DbParameterCollectionDbParameterCollection DbTransactionDbTransaction
DbProviderFactoryDbProviderFactory DbProviderFactoriesDbProviderFactories DbExceptionDbException
Usare una Provider FactoryUsare una Provider FactoryUsare una Provider FactoryUsare una Provider Factory• Importare il Namespace:Importare il Namespace:
using System.Data.Commonusing System.Data.Common
• Creare l’istanza della Factory:Creare l’istanza della Factory:static DbProviderFactory factory = static DbProviderFactory factory = DbProviderFactories.GetFactory("provider-name")DbProviderFactories.GetFactory("provider-name")
• Creare le istanze degli oggetti:Creare le istanze degli oggetti:DbConnection con = factory.CreateConnection()DbConnection con = factory.CreateConnection()
DbCommand cmd = con.CreateCommand()DbCommand cmd = con.CreateCommand()
• Importare il Namespace:Importare il Namespace:using System.Data.Commonusing System.Data.Common
• Creare l’istanza della Factory:Creare l’istanza della Factory:static DbProviderFactory factory = static DbProviderFactory factory = DbProviderFactories.GetFactory("provider-name")DbProviderFactories.GetFactory("provider-name")
• Creare le istanze degli oggetti:Creare le istanze degli oggetti:DbConnection con = factory.CreateConnection()DbConnection con = factory.CreateConnection()
DbCommand cmd = con.CreateCommand()DbCommand cmd = con.CreateCommand()
Provider EnumerationProvider EnumerationProvider EnumerationProvider Enumeration
• Ogni provider ha un nome invarianteOgni provider ha un nome invariante– Per esempio: "System.Data.SqlClient", "System.Data.OracleClient"Per esempio: "System.Data.SqlClient", "System.Data.OracleClient"
• Ottenere la lista delle provider factory Ottenere la lista delle provider factory installateinstallateDataTable dt = DataTable dt = DbProviderFactories.GetFactoryClasses()DbProviderFactories.GetFactoryClasses()
DbProviderFactory factory = DbProviderFactory factory = DbProviderFactories.GetFactory(dt.Rows[x])DbProviderFactories.GetFactory(dt.Rows[x])
– ... o ...... o ...DbProviderFactory factory = DbProviderFactory factory = DbProviderFactories.GetFactory( dt.Select("InvariDbProviderFactories.GetFactory( dt.Select("InvariantName='System.Data.SqlClient'") [0]antName='System.Data.SqlClient'") [0]["InvariantName"].ToString());["InvariantName"].ToString());
• Ogni provider ha un nome invarianteOgni provider ha un nome invariante– Per esempio: "System.Data.SqlClient", "System.Data.OracleClient"Per esempio: "System.Data.SqlClient", "System.Data.OracleClient"
• Ottenere la lista delle provider factory Ottenere la lista delle provider factory installateinstallateDataTable dt = DataTable dt = DbProviderFactories.GetFactoryClasses()DbProviderFactories.GetFactoryClasses()
DbProviderFactory factory = DbProviderFactory factory = DbProviderFactories.GetFactory(dt.Rows[x])DbProviderFactories.GetFactory(dt.Rows[x])
– ... o ...... o ...DbProviderFactory factory = DbProviderFactory factory = DbProviderFactories.GetFactory( dt.Select("InvariDbProviderFactories.GetFactory( dt.Select("InvariantName='System.Data.SqlClient'") [0]antName='System.Data.SqlClient'") [0]["InvariantName"].ToString());["InvariantName"].ToString());
Provider EnumerationProvider Enumeration
usando una Provider Factoryusando una Provider Factory
Provider EnumerationProvider Enumeration
usando una Provider Factoryusando una Provider Factory
Performance ImprovementsPerformance ImprovementsPerformance ImprovementsPerformance Improvements• Indicizzazione interna delle righe. I tempi Indicizzazione interna delle righe. I tempi
di:di:– InsertInsert e e deletedelete crescono logaritmicamente crescono logaritmicamente– updateupdate rimangono quasi costanti rimangono quasi costanti
• Serializzazione binariaSerializzazione binaria– I DataSet I DataSet v1.xv1.x erano sempre serializzati in erano sempre serializzati in
XMLXML• Vantaggioso per lo scambio dati, ma penalizzante Vantaggioso per lo scambio dati, ma penalizzante
per le performanceper le performance– La v2.0 supporta la serializzazione binariaLa v2.0 supporta la serializzazione binaria
• È più veloce ed occupa meno spazioÈ più veloce ed occupa meno spazio• Basta usare: DataSet.RemotingFormat = Basta usare: DataSet.RemotingFormat =
SerializationFormat.BinarySerializationFormat.Binary
• Indicizzazione interna delle righe. I tempi Indicizzazione interna delle righe. I tempi di:di:– InsertInsert e e deletedelete crescono logaritmicamente crescono logaritmicamente– updateupdate rimangono quasi costanti rimangono quasi costanti
• Serializzazione binariaSerializzazione binaria– I DataSet I DataSet v1.xv1.x erano sempre serializzati in erano sempre serializzati in
XMLXML• Vantaggioso per lo scambio dati, ma penalizzante Vantaggioso per lo scambio dati, ma penalizzante
per le performanceper le performance– La v2.0 supporta la serializzazione binariaLa v2.0 supporta la serializzazione binaria
• È più veloce ed occupa meno spazioÈ più veloce ed occupa meno spazio• Basta usare: DataSet.RemotingFormat = Basta usare: DataSet.RemotingFormat =
SerializationFormat.BinarySerializationFormat.Binary
Performance inserimento Performance inserimento righerighe
Performance inserimento Performance inserimento righerighe
0
5 0 0
1 0 0 0
1 5 0 0
2 0 0 0
2 5 0 0
3 0 0 0
3 5 0 0
4 0 0 0
0 1 0 0 0 0 2 0 0 0 0 3 0 0 0 0 4 0 0 0 0 5 0 0 0 0 6 0 0 0 0 7 0 0 0 0
N u m b e r o f R o w s
Tim
e i
n M
illi
se
co
nd
s
E v e re t tW h id b e y
DataRow Insertion Perf ImprovementDataRow Insertion Perf ImprovementDataRow Insertion Perf ImprovementDataRow Insertion Perf Improvement
Binary vs. XML SerializationBinary vs. XML SerializationBinary vs. XML SerializationBinary vs. XML Serialization
1 0 0 1 0 0 0 1 0 0 0 0 1 0 0 0 0 0
R o w s i n D a t a S e t
End-
to-E
nd T
ime
(low
er is
be
tter
)
X m l
B i n a r y
Incrementi fino ad 80 xIncrementi fino ad 80 x
Popolare un DataSetPopolare un DataSetPopolare un DataSetPopolare un DataSet
• DataAdapter.Fill(DataSet, "table-name")DataAdapter.Fill(DataSet, "table-name")– Nuovo: proprietà DataAdapter.FillLoadOption e Nuovo: proprietà DataAdapter.FillLoadOption e
AcceptChangesDuringUpdateAcceptChangesDuringUpdate
• Nuovo: metodo DataSet.LoadNuovo: metodo DataSet.Load– Load(DataReader [, load-option] [, tables-Load(DataReader [, load-option] [, tables-
array])array])
• Nuovo: LoadOption enumerationNuovo: LoadOption enumeration– PreserveCurrentValues | UpdateCurrentValues PreserveCurrentValues | UpdateCurrentValues
| OverwriteRow| OverwriteRow
• DataAdapter.Fill(DataSet, "table-name")DataAdapter.Fill(DataSet, "table-name")– Nuovo: proprietà DataAdapter.FillLoadOption e Nuovo: proprietà DataAdapter.FillLoadOption e
AcceptChangesDuringUpdateAcceptChangesDuringUpdate
• Nuovo: metodo DataSet.LoadNuovo: metodo DataSet.Load– Load(DataReader [, load-option] [, tables-Load(DataReader [, load-option] [, tables-
array])array])
• Nuovo: LoadOption enumerationNuovo: LoadOption enumeration– PreserveCurrentValues | UpdateCurrentValues PreserveCurrentValues | UpdateCurrentValues
| OverwriteRow| OverwriteRow
LoadOption EnumerationLoadOption EnumerationLoadOption EnumerationLoadOption EnumerationRowState of RowState of Existing RowExisting Row
PreserveCurrentValuesPreserveCurrentValues(the default value)(the default value)
UpdateCurrentValuesUpdateCurrentValues OverwriteRow OverwriteRow
AddedAdded Current = ExistingCurrent = ExistingOriginal = IncomingOriginal = IncomingRowState = ModifiedRowState = Modified
Current = IncomingCurrent = IncomingOriginal = ExistingOriginal = ExistingRowState = AddedRowState = Added
Current = IncomingCurrent = IncomingOriginal = IncomingOriginal = IncomingRowState = UnchangedRowState = Unchanged
ModifiedModified Current = ExistingCurrent = ExistingOriginal = IncomingOriginal = IncomingRowState = ModifiedRowState = Modified
Current = IncomingCurrent = IncomingOriginal = ExistingOriginal = ExistingRowState = ModifiedRowState = Modified
Current = IncomingCurrent = IncomingOriginal = IncomingOriginal = IncomingRowState = UnchangedRowState = Unchanged
DeletedDeleted Current = ExistingCurrent = ExistingOriginal = IncomingOriginal = IncomingRowState = DeletedRowState = Deleted
* Undo Delete * Undo Delete Current = IncomingCurrent = IncomingOriginal = ExistingOriginal = ExistingRowState = ModifiedRowState = Modified
* Undo Delete * Undo Delete Current = IncomingCurrent = IncomingOriginal = IncomingOriginal = IncomingRowState = UnchangedRowState = Unchanged
UnchangedUnchanged Current = IncomingCurrent = IncomingOriginal = IncomingOriginal = IncomingRowState = UnchangedRowState = Unchanged
Current = IncomingCurrent = IncomingOriginal = ExistingOriginal = Existing* if new value = existing value: * if new value = existing value: RowState = Unchanged RowState = Unchanged * else:* else: RowState = ModifiedRowState = Modified
Current = IncomingCurrent = IncomingOriginal = IncomingOriginal = IncomingRowState = UnchangedRowState = Unchanged
No matching No matching existing row in the existing row in the tabletable
Current = IncomingCurrent = IncomingOriginal = IncomingOriginal = IncomingRowState = UnchangedRowState = Unchanged
Current = IncomingCurrent = IncomingOriginal = ExistingOriginal = ExistingRowState = AddedRowState = Added
Current = IncomingCurrent = IncomingOriginal = IncomingOriginal = IncomingRowState = UnchangedRowState = Unchanged
Nuove featureNuove featureNuove featureNuove feature
• RowState modificabileRowState modificabile
– Nuovi metodi: DataRow.SetAdded e Nuovi metodi: DataRow.SetAdded e
DataRow.SetModifiedDataRow.SetModified
• Metodo DataSet.GetDataReaderMetodo DataSet.GetDataReader
– Restituisce un DataTableReaderRestituisce un DataTableReader
– E’ possibile specificare quali tabelle includereE’ possibile specificare quali tabelle includere
• RowState modificabileRowState modificabile
– Nuovi metodi: DataRow.SetAdded e Nuovi metodi: DataRow.SetAdded e
DataRow.SetModifiedDataRow.SetModified
• Metodo DataSet.GetDataReaderMetodo DataSet.GetDataReader
– Restituisce un DataTableReaderRestituisce un DataTableReader
– E’ possibile specificare quali tabelle includereE’ possibile specificare quali tabelle includere
Popolare un DataSet con un DataReader Popolare un DataSet con un DataReader e usare un DataTableReader.e usare un DataTableReader.
Popolare un DataSet con un DataReader Popolare un DataSet con un DataReader e usare un DataTableReader.e usare un DataTableReader.
DataTable “stand-alone”DataTable “stand-alone”DataTable “stand-alone”DataTable “stand-alone”• Operazioni tipiche del DataSet supportate anche Operazioni tipiche del DataSet supportate anche
per le DataTable:per le DataTable:
– ReadXml, ReadXmlSchema, WriteXml, ReadXml, ReadXmlSchema, WriteXml,
WriteXmlSchema, Clear, Clone, Copy, Merge, WriteXmlSchema, Clear, Clone, Copy, Merge,
GetChanges GetChanges
• La classe DataTable ora supporta la La classe DataTable ora supporta la
serializzazione:serializzazione:
– Perchè implementa Perchè implementa IXmlSerializableIXmlSerializable
– E’ possibile restituire una istanza di DataTable mediante E’ possibile restituire una istanza di DataTable mediante
Web Service o RemotingWeb Service o Remoting
• Operazioni tipiche del DataSet supportate anche Operazioni tipiche del DataSet supportate anche
per le DataTable:per le DataTable:
– ReadXml, ReadXmlSchema, WriteXml, ReadXml, ReadXmlSchema, WriteXml,
WriteXmlSchema, Clear, Clone, Copy, Merge, WriteXmlSchema, Clear, Clone, Copy, Merge,
GetChanges GetChanges
• La classe DataTable ora supporta la La classe DataTable ora supporta la
serializzazione:serializzazione:
– Perchè implementa Perchè implementa IXmlSerializableIXmlSerializable
– E’ possibile restituire una istanza di DataTable mediante E’ possibile restituire una istanza di DataTable mediante
Web Service o RemotingWeb Service o Remoting
Popolare ed usare DataTablePopolare ed usare DataTablePopolare ed usare DataTablePopolare ed usare DataTable
• DataAdapter.Fill(DataTable)DataAdapter.Fill(DataTable)
• DataAdapter.Fill(DataTable[ ], …)DataAdapter.Fill(DataTable[ ], …)– Permette di selezionare un sottoinsieme di righePermette di selezionare un sottoinsieme di righe
• DataAdapter.Update(DataTable)DataAdapter.Update(DataTable)
• DataTable.Load(DataReader [, load-option] DataTable.Load(DataReader [, load-option] [, FillErrorEventHandler])[, FillErrorEventHandler])– Nuovi metodi: BeginLoadData, Load, EndLoadDataNuovi metodi: BeginLoadData, Load, EndLoadData
• DataTable.GetDataReader methodDataTable.GetDataReader method– Ottiene uno stream da una DataTableOttiene uno stream da una DataTable
• DataAdapter.Fill(DataTable)DataAdapter.Fill(DataTable)
• DataAdapter.Fill(DataTable[ ], …)DataAdapter.Fill(DataTable[ ], …)– Permette di selezionare un sottoinsieme di righePermette di selezionare un sottoinsieme di righe
• DataAdapter.Update(DataTable)DataAdapter.Update(DataTable)
• DataTable.Load(DataReader [, load-option] DataTable.Load(DataReader [, load-option] [, FillErrorEventHandler])[, FillErrorEventHandler])– Nuovi metodi: BeginLoadData, Load, EndLoadDataNuovi metodi: BeginLoadData, Load, EndLoadData
• DataTable.GetDataReader methodDataTable.GetDataReader method– Ottiene uno stream da una DataTableOttiene uno stream da una DataTable
Update BatchUpdate BatchUpdate BatchUpdate Batch
• In 1.1, gli update dei DataSet sono eseguiti In 1.1, gli update dei DataSet sono eseguiti riga per rigariga per riga
• Il batch update riduce round-trip lungo la Il batch update riduce round-trip lungo la reterete
• DataAdapter.UpdateBatchSize = DataAdapter.UpdateBatchSize = batch_sizebatch_size
• Funziona all’interno di transazioniFunziona all’interno di transazioni• Funziona con SQL Server 7.0, 2000, 2005Funziona con SQL Server 7.0, 2000, 2005• Disponibile anche per il provider Disponibile anche per il provider
OracleClientOracleClient
• In 1.1, gli update dei DataSet sono eseguiti In 1.1, gli update dei DataSet sono eseguiti riga per rigariga per riga
• Il batch update riduce round-trip lungo la Il batch update riduce round-trip lungo la reterete
• DataAdapter.UpdateBatchSize = DataAdapter.UpdateBatchSize = batch_sizebatch_size
• Funziona all’interno di transazioniFunziona all’interno di transazioni• Funziona con SQL Server 7.0, 2000, 2005Funziona con SQL Server 7.0, 2000, 2005• Disponibile anche per il provider Disponibile anche per il provider
OracleClientOracleClient
DataTable “stand-alone”DataTable “stand-alone”DataTable “stand-alone”DataTable “stand-alone”
Comandi asincroniComandi asincroniComandi asincroniComandi asincroni
• Ideali per eseguire molteplici queryIdeali per eseguire molteplici query• Il “solito” Async Pattern: Il “solito” Async Pattern: BeginBeginxxxxxx e e EndEndxxxxxx
• Supporta Polling, Wait e CallbackSupporta Polling, Wait e Callback• Non dovrebbe essere usato in abbinamento Non dovrebbe essere usato in abbinamento
a MARSa MARS– usate una connessione per ogni Commandusate una connessione per ogni Command
• Aggiungere "async=true" alla connection Aggiungere "async=true" alla connection stringstring
• Ideali per eseguire molteplici queryIdeali per eseguire molteplici query• Il “solito” Async Pattern: Il “solito” Async Pattern: BeginBeginxxxxxx e e EndEndxxxxxx
• Supporta Polling, Wait e CallbackSupporta Polling, Wait e Callback• Non dovrebbe essere usato in abbinamento Non dovrebbe essere usato in abbinamento
a MARSa MARS– usate una connessione per ogni Commandusate una connessione per ogni Command
• Aggiungere "async=true" alla connection Aggiungere "async=true" alla connection stringstring
~ 3 secs
Application
Esecuzione sincronaEsecuzione sincronaEsecuzione sincronaEsecuzione sincrona
Rowset 1
Rowset 2
Rowset 3
Tempo per visualizzare i dati:
Database2Latency 8 secs
Database3Latency 5 secs
Connection
Connection
~ 11 secs ~ 16 secs
Data 1
Data 1
Data 1Data 1Data 1
Data 1
Data 1
Data 1
Data 1
Data 1Data 1Data 1
Data 1
Data 1
Data 1
Data 1
Data 1Data 1Data 1
Data 1
Data 1
Data 1
Data 1
Data 1Data 1Data 1
Data 1
Data 1
Data 1
Data 1
Data 1Data 1Data 1
Data 1
Data 1
Data 1
Data 1
Data 1Data 1Data 1
Data 1
Data 1
Data 1
Data 1
Data 1Data 1Data 1
Data 1
Data 1
Data 1
Data 1
Data 1Data 1Data 1
Data 1
Data 1
Data 1
Data 1
Data 1Data 1Data 1
Data 1
Data 1
Data 1
Data 1
Data 1Data 1Data 1
Data 1
Data 1
Data 1
Data 1
Data 1Data 1Data 1
Data 1
Data 1
Data 1
Data 1
Data 1Data 1Data 1
Data 1
Data 1
Database1Latency 3 secsConnection
Application
Esecuzione asincronaEsecuzione asincronaEsecuzione asincronaEsecuzione asincrona
Rowset 1
Rowset 2
Rowset 3
Connection1
Connection2
Connection3
~ 8 secs Tempo per visualizzare i dati:
Data 1
Data 1
Data 1Data 1Data 1
Data 1
Data 1
Data 1
Data 1
Data 1Data 1Data 1
Data 1
Data 1
Data 1
Data 1
Data 1Data 1Data 1
Data 1
Data 1
Data 1
Data 1
Data 1Data 1Data 1
Data 1
Data 1
Data 1
Data 1
Data 1Data 1Data 1
Data 1
Data 1
Data 1
Data 1
Data 1Data 1Data 1
Data 1
Data 1
Data 1
Data 1
Data 1Data 1Data 1
Data 1
Data 1
Data 1
Data 1
Data 1Data 1Data 1
Data 1
Data 1
Data 1
Data 1
Data 1Data 1Data 1
Data 1
Data 1
Data 1
Data 1
Data 1Data 1Data 1
Data 1
Data 1
Data 1
Data 1
Data 1Data 1Data 1
Data 1
Data 1
Data 1
Data 1
Data 1Data 1Data 1
Data 1
Data 1
Database1Latency 3 secs
Database2Latency 8 secs
Database3Latency 5 secs
Esecuzione asincrona: Esecuzione asincrona: Polling ModelPolling Model
Esecuzione asincrona: Esecuzione asincrona: Polling ModelPolling Model
• Avviare un comando asincrono:Avviare un comando asincrono:Dim result As IAsyncResult = Dim result As IAsyncResult = MyCommand.BeginExecuteReader()MyCommand.BeginExecuteReader()
• Aspettare fino al termine della Aspettare fino al termine della esecuzione:esecuzione:While Not result.IsCompletedWhile Not result.IsCompleted
‘‘Codice da eseguireCodice da eseguire
End WhileEnd While
• Recuperare i risultati:Recuperare i risultati:Dim reader As SqlDataReader = Dim reader As SqlDataReader = MyCommand.EndExecuteReader(result )MyCommand.EndExecuteReader(result )
• Avviare un comando asincrono:Avviare un comando asincrono:Dim result As IAsyncResult = Dim result As IAsyncResult = MyCommand.BeginExecuteReader()MyCommand.BeginExecuteReader()
• Aspettare fino al termine della Aspettare fino al termine della esecuzione:esecuzione:While Not result.IsCompletedWhile Not result.IsCompleted
‘‘Codice da eseguireCodice da eseguire
End WhileEnd While
• Recuperare i risultati:Recuperare i risultati:Dim reader As SqlDataReader = Dim reader As SqlDataReader = MyCommand.EndExecuteReader(result )MyCommand.EndExecuteReader(result )
Esecuzione asincrona: Wait Esecuzione asincrona: Wait (All) Model(All) Model
Esecuzione asincrona: Wait Esecuzione asincrona: Wait (All) Model(All) Model
• Avviare uno o più comandi asincroni:Avviare uno o più comandi asincroni:Dim resultDim resultxx As IAsyncResult = As IAsyncResult = MyCommand.BeginExecuteReader()MyCommand.BeginExecuteReader()
• Attendere il completamento di tutti i Attendere il completamento di tutti i comandi:comandi:WaitHandle.WaitAll(New WaitHandle() WaitHandle.WaitAll(New WaitHandle() {result1.AsyncWaitHandle, {result1.AsyncWaitHandle, result2.AsyncWaitHandle, result2.AsyncWaitHandle, result3.AsyncWaitHandle}, timeout - ms, True)result3.AsyncWaitHandle}, timeout - ms, True)
• Recuperare i risultati:Recuperare i risultati:Dim reader As SqlDataReader = Dim reader As SqlDataReader = MyCommand.EndExecuteReader(resultMyCommand.EndExecuteReader(resultxx))
• Ideale per le Web Application ASP.NETIdeale per le Web Application ASP.NET
• Avviare uno o più comandi asincroni:Avviare uno o più comandi asincroni:Dim resultDim resultxx As IAsyncResult = As IAsyncResult = MyCommand.BeginExecuteReader()MyCommand.BeginExecuteReader()
• Attendere il completamento di tutti i Attendere il completamento di tutti i comandi:comandi:WaitHandle.WaitAll(New WaitHandle() WaitHandle.WaitAll(New WaitHandle() {result1.AsyncWaitHandle, {result1.AsyncWaitHandle, result2.AsyncWaitHandle, result2.AsyncWaitHandle, result3.AsyncWaitHandle}, timeout - ms, True)result3.AsyncWaitHandle}, timeout - ms, True)
• Recuperare i risultati:Recuperare i risultati:Dim reader As SqlDataReader = Dim reader As SqlDataReader = MyCommand.EndExecuteReader(resultMyCommand.EndExecuteReader(resultxx))
• Ideale per le Web Application ASP.NETIdeale per le Web Application ASP.NET
Esecuzione asincrona: Wait Esecuzione asincrona: Wait (Any) Model(Any) Model
Esecuzione asincrona: Wait Esecuzione asincrona: Wait (Any) Model(Any) Model
• Avviare uno o più comandi asincroni come array di Avviare uno o più comandi asincroni come array di istanze di IAsyncResult:istanze di IAsyncResult:Dim resultDim resultxx As IAsyncResult = As IAsyncResult =
MyCommand.BeginExecuteReader()MyCommand.BeginExecuteReader()
• Attendere il completamento di ogni comando:Attendere il completamento di ogni comando:Dim i As IntegerDim i As IntegerFor i = 0 To result_array.LengthFor i = 0 To result_array.Length
index = WaitHandle.WaitAny(result_array,index = WaitHandle.WaitAny(result_array, timeout, true)timeout, true)
Select Case indexSelect Case indexCase 0Case 0
Dim reader As SqlDataReader =Dim reader As SqlDataReader = MyCommand.EndExecuteReader(resultMyCommand.EndExecuteReader(resultxx))
......End SelectEnd Select
End ForEnd For
• Avviare uno o più comandi asincroni come array di Avviare uno o più comandi asincroni come array di istanze di IAsyncResult:istanze di IAsyncResult:Dim resultDim resultxx As IAsyncResult = As IAsyncResult =
MyCommand.BeginExecuteReader()MyCommand.BeginExecuteReader()
• Attendere il completamento di ogni comando:Attendere il completamento di ogni comando:Dim i As IntegerDim i As IntegerFor i = 0 To result_array.LengthFor i = 0 To result_array.Length
index = WaitHandle.WaitAny(result_array,index = WaitHandle.WaitAny(result_array, timeout, true)timeout, true)
Select Case indexSelect Case indexCase 0Case 0
Dim reader As SqlDataReader =Dim reader As SqlDataReader = MyCommand.EndExecuteReader(resultMyCommand.EndExecuteReader(resultxx))
......End SelectEnd Select
End ForEnd For
Esecuzione asincrona: Esecuzione asincrona: Callback ModelCallback Model
Esecuzione asincrona: Esecuzione asincrona: Callback ModelCallback Model
• Avviare l’esecuzione, specificando la Avviare l’esecuzione, specificando la funzione di callback e il command come funzione di callback e il command come AsyncState:AsyncState:MyCommand.BeginExecuteReader(new MyCommand.BeginExecuteReader(new AsyncCallback(MyCallback), cmd)AsyncCallback(MyCallback), cmd)
• Creare il gestore del callback:Creare il gestore del callback:Sub MyCallback(ByVal result As IAsyncResult) Sub MyCallback(ByVal result As IAsyncResult)
Dim cmd As SqlCommand = Dim cmd As SqlCommand = DirectCast(result.AsyncState, SqlCommand)DirectCast(result.AsyncState, SqlCommand)
Dim reader As SqlDataReader = Dim reader As SqlDataReader = cmd.EndExecuteReader(result)cmd.EndExecuteReader(result)
End SubEnd Sub
• Avviare l’esecuzione, specificando la Avviare l’esecuzione, specificando la funzione di callback e il command come funzione di callback e il command come AsyncState:AsyncState:MyCommand.BeginExecuteReader(new MyCommand.BeginExecuteReader(new AsyncCallback(MyCallback), cmd)AsyncCallback(MyCallback), cmd)
• Creare il gestore del callback:Creare il gestore del callback:Sub MyCallback(ByVal result As IAsyncResult) Sub MyCallback(ByVal result As IAsyncResult)
Dim cmd As SqlCommand = Dim cmd As SqlCommand = DirectCast(result.AsyncState, SqlCommand)DirectCast(result.AsyncState, SqlCommand)
Dim reader As SqlDataReader = Dim reader As SqlDataReader = cmd.EndExecuteReader(result)cmd.EndExecuteReader(result)
End SubEnd Sub
Esecuzione di comandi asincroniEsecuzione di comandi asincroniEsecuzione di comandi asincroniEsecuzione di comandi asincroni
DataReader: PagingDataReader: PagingDataReader: PagingDataReader: Paging• Il paging? Il paging? C’est plus facileC’est plus facile, col metodo , col metodo
ExecutePageReaderExecutePageReader• Accetta l’indice della prima riga e il numero di righe da restituireAccetta l’indice della prima riga e il numero di righe da restituire
• Non garantisce consistenzaNon garantisce consistenza• Senza il supporto di una transazione, alcune righe potrebbero Senza il supporto di una transazione, alcune righe potrebbero
essere saltate o ripetuteessere saltate o ripetute
• Moooolto più veloce che leggere tutte le righe Moooolto più veloce che leggere tutte le righe ed ignorare quelle non desiderateed ignorare quelle non desiderate– E’ comunque preferibile eseguire una query “mirata”E’ comunque preferibile eseguire una query “mirata”
• Il paging? Il paging? C’est plus facileC’est plus facile, col metodo , col metodo ExecutePageReaderExecutePageReader• Accetta l’indice della prima riga e il numero di righe da restituireAccetta l’indice della prima riga e il numero di righe da restituire
• Non garantisce consistenzaNon garantisce consistenza• Senza il supporto di una transazione, alcune righe potrebbero Senza il supporto di una transazione, alcune righe potrebbero
essere saltate o ripetuteessere saltate o ripetute
• Moooolto più veloce che leggere tutte le righe Moooolto più veloce che leggere tutte le righe ed ignorare quelle non desiderateed ignorare quelle non desiderate– E’ comunque preferibile eseguire una query “mirata”E’ comunque preferibile eseguire una query “mirata”
Troppo bello per essere vero? Lo pensa anche Troppo bello per essere vero? Lo pensa anche Microsoft, infatti ha rimosso il metodo nella Microsoft, infatti ha rimosso il metodo nella beta2beta2
Troppo bello per essere vero? Lo pensa anche Troppo bello per essere vero? Lo pensa anche Microsoft, infatti ha rimosso il metodo nella Microsoft, infatti ha rimosso il metodo nella beta2beta2
Multiple Active Result Sets Multiple Active Result Sets (MARS)(MARS)
Multiple Active Result Sets Multiple Active Result Sets (MARS)(MARS)
• (Ri)Conoscete questo messaggio? (Ri)Conoscete questo messaggio? – System.InvalidOperationException: There is System.InvalidOperationException: There is
already an open DataReader associated with this already an open DataReader associated with this Connection which must be closed first.Connection which must be closed first.
• (Ri)Conoscete questo messaggio? (Ri)Conoscete questo messaggio? – System.InvalidOperationException: There is System.InvalidOperationException: There is
already an open DataReader associated with this already an open DataReader associated with this Connection which must be closed first.Connection which must be closed first.
Multiple Active Results Sets Multiple Active Results Sets (MARS)(MARS)
Multiple Active Results Sets Multiple Active Results Sets (MARS)(MARS)
• Mantiene disponibile una connessione Mantiene disponibile una connessione quando apriamo un SqlDataReader al fine quando apriamo un SqlDataReader al fine di poter:di poter:– Eseguire un’altra query per ottenere un Eseguire un’altra query per ottenere un
DataReader/XmlReaderDataReader/XmlReader– Eseguire comandi DMLEseguire comandi DML
• Possono essere attivi differenti result set Possono essere attivi differenti result set contemporaeamentecontemporaeamente– alternare fetch ad ogni readeralternare fetch ad ogni reader– Alternare query che non restituiscono readerAlternare query che non restituiscono reader
• Mantiene disponibile una connessione Mantiene disponibile una connessione quando apriamo un SqlDataReader al fine quando apriamo un SqlDataReader al fine di poter:di poter:– Eseguire un’altra query per ottenere un Eseguire un’altra query per ottenere un
DataReader/XmlReaderDataReader/XmlReader– Eseguire comandi DMLEseguire comandi DML
• Possono essere attivi differenti result set Possono essere attivi differenti result set contemporaeamentecontemporaeamente– alternare fetch ad ogni readeralternare fetch ad ogni reader– Alternare query che non restituiscono readerAlternare query che non restituiscono reader
Alternare Results SetAlternare Results SetAlternare Results SetAlternare Results Set
• Scenario tipico:Scenario tipico:– Recuperare la lista dei clienti e scorrerlaRecuperare la lista dei clienti e scorrerla– Per ogni cliente, recuperare la lista degli ordiniPer ogni cliente, recuperare la lista degli ordini– Per ogni ordine, recuperarne il dettaglioPer ogni ordine, recuperarne il dettaglio
• Nella v1, per ottenere ciò usando dei reader Nella v1, per ottenere ciò usando dei reader erano necessarie differenti connessionierano necessarie differenti connessioni
• Mediante MARS, è sufficiente una sola Mediante MARS, è sufficiente una sola connessione se:connessione se:– I dati risiedono nello stesso databaseI dati risiedono nello stesso database– Usiamo SQL Server 2005/MDAC9Usiamo SQL Server 2005/MDAC9
• Scenario tipico:Scenario tipico:– Recuperare la lista dei clienti e scorrerlaRecuperare la lista dei clienti e scorrerla– Per ogni cliente, recuperare la lista degli ordiniPer ogni cliente, recuperare la lista degli ordini– Per ogni ordine, recuperarne il dettaglioPer ogni ordine, recuperarne il dettaglio
• Nella v1, per ottenere ciò usando dei reader Nella v1, per ottenere ciò usando dei reader erano necessarie differenti connessionierano necessarie differenti connessioni
• Mediante MARS, è sufficiente una sola Mediante MARS, è sufficiente una sola connessione se:connessione se:– I dati risiedono nello stesso databaseI dati risiedono nello stesso database– Usiamo SQL Server 2005/MDAC9Usiamo SQL Server 2005/MDAC9
Interleaved Results Sets Interleaved Results Sets ExampleExample
Interleaved Results Sets Interleaved Results Sets ExampleExample
Dim parentReader As DataReader = Dim parentReader As DataReader = Command1.ExecuteReader()Command1.ExecuteReader()
While parentReader.Read()While parentReader.Read()
' process parent row data here' process parent row data here
' then get rowset from child table' then get rowset from child table
Command2.Parameters("@id").Value = Command2.Parameters("@id").Value = parentReader("id")parentReader("id")
Dim childReader As DataReader = Dim childReader As DataReader = Command2.ExecuteReader()Command2.ExecuteReader()
' process child rows here' process child rows here
childReader.Close()childReader.Close()
End WhileEnd While
parentReader.Close()parentReader.Close()
Dim parentReader As DataReader = Dim parentReader As DataReader = Command1.ExecuteReader()Command1.ExecuteReader()
While parentReader.Read()While parentReader.Read()
' process parent row data here' process parent row data here
' then get rowset from child table' then get rowset from child table
Command2.Parameters("@id").Value = Command2.Parameters("@id").Value = parentReader("id")parentReader("id")
Dim childReader As DataReader = Dim childReader As DataReader = Command2.ExecuteReader()Command2.ExecuteReader()
' process child rows here' process child rows here
childReader.Close()childReader.Close()
End WhileEnd While
parentReader.Close()parentReader.Close()
LinksLinksLinksLinks
http://www.ugidotnet.org
http://forum.ugidotnet.org
http://mobile.ugidotnet.org