3. ADO.NET: introduzione
ADO.NET è il componente per l'accesso 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 e
tipi,che gestiscono l‟accesso ai dati all‟interno del .NET framework, di cui
sono parte integrante, e sono organizzate in namespace a partire da
System.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 è la
modalità 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.NET
Command XxxCommand
ADO
DataSet
Recordset XxxDataReader
XxxDataAdapter
XXX sarà sosituito dal prefisso relativo all‟RDBMS 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
9. ADO.NET: vantaggi
Alta Interoperabilità grazie all‟uso di XML:
Standard aperti per i dati che si autodescrivono
Informazioni facilmente leggibili
Uso interno della mappatura ma utilizzabile esternamente, per poter
leggere, scrivere e sostituire i dati;
Elevata Scalabilità grazie all‟uso 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: architettura
Come tutti gli altri componenti del .NET Framework, ADO.NET consiste di un insieme di
oggetti che interagiscono fra loro per svolgere una determinata funzione (è appunto un
framework). 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 Provider Data Consumer
.NET Data Storage
Connection DataSet WinForm
Command DataTables
WebForm
DataAdapter XMLData
DataReader XMLDataSchema Altri
XML Entrambi i componenti possono
Data Source
comunicare con i Data Consumers ,
ovvero i fruitori dei loro servizi, come, ad
esempio una WinForm o una WebForm.
11. ADO.NET: architettura
.NET Application
DataSet
System.Data.Oracle System.Data.SqlClient System.Data.OleDb System.Data.Odbc
OLE DB
OLE DB Provider
ODBC
Non-relational
Oracle SQL Server Other DBMS sources
12. ADO.NET: Data Provider
Attraverso il Data Provider è possibile ottenere/inviare dati da/a un qualsiasi tipo
di sorgente dati:
•Relazionale
•XML
•Custom
Ogni sorgente dati ha un proprio Data Provider ed ognuno di essi espone gli stessi
metodi (implementando le stesse interfacce o classi base) di base con opportuni
prefissi 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.
un’istruzione SQL)
• xxxDataReader: permette di ottenere in modo veloce, read-only e forward-only i dati
dalla sorgente dati
• xxxDataAdapter fornisce il meccanismo di interazione tra la connessione e il data set
13. ADO.NET: SQL Data Provider Object Model
SqlConnection
SqlCommand
System.Xml.XmlReader SqlDataReader SqlParameterCollection
Object SqlParameter
Common Language Runtime
SQL CLIENT
TDS SQL
PARSER SERVER
14. ADO.NET: OleDB Data Provider Object Model
OleDbConnection
.CreateCommand
.ExecuteReader
OleDbCommand
.Connection
.Parameters
OleDbDataReader OleDbParameterCollection
.Add
.Item .CreateParameter .Item
Object OleDbParameter
Common Language Runtime
OleDb
Provider
OLEDB
Data Source
Managed Relazionale
Provider e non
15. ADO.NET: ODBC Data Provider Object Model
OdbcConnection
.CreateCommand
.ExecuteReader
OdbcCommand
.Connection
.Parameters
OdbcDataReader OdbcParameterCollection
.Add
.Item .CreateParameter .Item
Object OdbcParameter
Common Language Runtime
ODBC
DRIVER
ODBC
Managed Data Source
Relazionale
Provider
16. ADO.NET: DB2 Data Provider
L‟accesso a DB2 di IBM può avvenire attraverso i provider OleDb o ODBC illustrati
prima oppure attraverso uno specifico managed provider sviluppato da IBM
Application Application Application
System.Data.OleDb Microsft.Data.ODBC IBM.Data.DB2
OLE DB .Net ODBC .Net DB2 .Net Data
Data Provider Data Provider Provider
OleDbConnection OdbcConnection DB2Connection
OleDbCommand OdbcCommand DB2Command
OleDbAdapter OdbcDataAdapter DB2DataAdapter
OleDbDataReader OdbcDataReader DB2DataReader
IBM DB2 OLE IBM DB2
DB Provider ODBC Driver
DB2
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 un‟
integrazione completa esponendo tutte le caratteristiche di un Oracle DB
In pù è disponibile l‟Oracle Connect per .NET per l‟uso con OleDB e Odbc
18. ADO.NET: Data Provider, Classe Connection
La classe Connection (simile a quella presente in ADO classico) implementa
l‟interfaccia 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 l‟interfaccia
IDBCommand
In base al risultato atteso è possiamo eseguire un comando attraverso metodi
specificatamente 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 o
numero di record modificati;
• ExecuteXMLReader()
• specifico per l‟accesso 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 SQLCommand
Vediamo un Dim rowsAffected As Integer
esempio Try
completo di ' Creo la connessione
utilizzo della sqlConn = New SQLConnection(myConnString)
classe ' Creo il comando
Command. sqlCmd = New SQLCommand()
' specifico il tipo di comando
Un oggetto With sqlCmd
Command può .CommandType = CommandType.Text
essere creato in .CommandText = "Insert Customers (Alias, CustomerName) _
Values ('myAlias','myName')"
due modi:
.Connection = sqlConn
• Mediante il End With
costruttore; ' apro la connessione
• Mediante il sqlConn.Open()
metodo ' eseguo il comando, vengono ritornate le righe inserite
CreateCom rowsAffected = sqlCmd.ExecuteNonQuery()
mand da Catch e As Exception
inocare ' gestisco l‟eccezione …
sull’oggetto Finally
connessione ' chiudo la connesione
sqlConn.Close()
End Try
21. ADO.NET: Data Provider, Classe Command & Stored Procedure
Attraverso la classe Command è possibile invocare una StoredProcedure (se la
sorgete 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 è possibile
utilizzare 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 connessione
With sqlCmd
.CommandType = CommandType.StoredProcedure
.CommandText = "InsertCustomer"
.Connection = sqlConn
End With
' Definisco e aggiung un parametro alla relativa collection
param = 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 connessione
sqlConn.Open()
' Eseguo il comando
rowsAffected = 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))
Loop
myReader.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 XmlReader
Vediamo come utilizzare l’ExecuteXmlReader() 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, Transazioni
Le 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();
l‟equivalente 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 transizione
con 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, Exception
Eventuali errori durante l‟esecuzione di operazioni sulla fonte dati vengono
intercettati attraverso le eccezioni.
Ogni Managed providers implementa le proprie eccezioni derivanti da
•SqlException
•SqlError
L‟evento di base da gestire per cattuare le eccezioni è InfoMessage, gestibile
attraverso 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, Exception
public static int Main(string[] args) {
try Gestione
{ delle
SqlConnection conn = new SqlConnection(“ConnectionString”); eccezioni
// Associo un event handler all‟evento di InfoMessage
conn.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 Set
Permette di gestire i dati come se si disponesse di database relazionale
immagazzinato 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
Collezioni
DataSet
DataSet
DataRelationsCollection DataTableCollection
DataRelation DataTable
DataTable DataTable ConstraintCollection DataRowCollection DataColumnCollection
DataColumn DataRow Constraint DataRow DataColumn
32. ADO.NET: Ruolo del DataAdapter
Select
xxxCommand
xxxCommandBuilder
xxxDataAdapter
Insert
xxxCommand
xxxConnection
Update
xxxCommand
Delete
xxxCommand
Data
DataSet
34. ADO.NET: Popolare un Data Set
Essendo un Data Set una sorta di mini-db relazionale in memoria è possibile
popolarlo 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 classe
SqlDataAdapter che è il vero nodo di collegamento tra il “mondo” connesso e
quello disconnesso. Infatti il DataSet viene “riempito” dai dati e si può lavorare
in modalità disconessa.
Terminate le attività di modifica è possibile aggiornare la sorgente dati originale:
adaptSQL.Update (datPubs, "miaTabella")
35. ADO.NET: la proprietà DataRowSet
Ogni riga inserita nella rispettiva tabella ha uno stato contenuto della proprietà
RowState del DataRow. In pratica una riga modifica il proprio stato dopo ogni
modifica.
I valori che il RowState può assumere sono contenuti nell‟enumeratore
DataRowState:
Valore Descrizione
Added La riga è stata aggiunta alla tabella
Deleted La riga è contrassegnata per l’eliminazione 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
Unchanged Nessuna modifca è stata eseguita dall’ultima invocazione a
AcceptChanges. E’ anche lo stato di tutte le righe quando la
tabella viene creata
II 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 Tabella
Come esposto la potenza di un DataSet è quello di contenere più tabelle e le
relative 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 Customers
mySqlDataAdapter.SelectCommand.CommandText = "select * from orders"
mySqlDataAdapter.Fill(myDataSet,"Orders") Tabella Orders
DataSet: Customers
Orders
Data Tables
37. ADO.NET: Data Set, classe DataTable
Ogni elemento della proprietà Tables è un‟istanza della classe DataTable
Un 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 delle
proprie colonne mediante la proprietà Item
Vediamo un utilizzo di tali proprietà:
Dim numeroRighe As Int32 = unaTabella.Rows.Count
Dim indiceRiga As Int32
Dim unaRiga As DataRow
For indiceRiga = 0 To numeroRighe - 1
unaRiga = unaTabella.Rows(indiceRiga)
Dim nomeAutore As String = _
unaRiga.Item("au_fname").ToString()
Next
38. ADO.NET: Data Set, classe DataRelation
Oltre alla proprietà tables, fondamentale è Relations, una collezione di istanze
della 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 l‟integrità 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.
SetDefault Imposta al DefaultValue il valore delle righe correlate.
None Nessuna 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")
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
un‟estensione delle versioni precedenti non non introducendo alcuna
incompatibilità.
L‟utilizzo di classi base condivise e non di interfacce permette di implementare
un‟architettura 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-Independent
Db*Base implementation classes
3rd 3rd Layer
Sql OleDb ODBC Oracle
Party 1 Party 2 Provider-Specific
ADO.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 le
classiche interfacce IDB* e la relativa implementazione specifica. Il motivo dell‟introduzione di
tale 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 tecniche
esistenti nelle precedenti versioni senza alcuna modifica.
45. ADO.NET 2.0: Classi Provider Indipendent
Le nuove classi base sono definite nel namespace System.Data.Commamd
Di seguito elenchiamo le più comuni:
DbCommand DbCommandBuilder DbConnection
DataAdapter DbDataAdapter DbDataReader
DbParameter DbParameterCollection DbTransaction
DbProviderFactory DbProviderFactories DbException
47. ADO.NET 2.0: il Pattern Factory
Il Pattern Factory (classificato come Creational Pattern) ha lo scopo di creare facilmente
nuovi 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 namespace
System.Data.Common
Come si usa:
1. Importare il namespace System.Dta.Common
2. Creare l‟istanza 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 Enumerator
Dove recuperiamo i nomi dei managed provider disponibili?
Assodato che ogni provider ha un nome invariante
per 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 Improvements
Nella versione 1.x Ado.Net offriva ottime performance per l‟inserimento di dati
all‟interno dei DataSet, ma gli aggiornamenti soffrivano del numero di righe presenti
al suo interno.
La versione 2.0 introduce una indicizzazione interna delle righe per ottimizzare le
prestazioni. Infatti i tempi di:
• Insert e Delete crescono logaritmicamente (tempi necessari
all‟aggiornamento degli indici);
•Update rimangono quasi costanti (grazie all‟accesso delle righe tramite gli
indici)
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 scambio
dati, ma penalizzante per le performance.
La v2.0 supporta la serializzazione binaria che è più veloce ed occupa meno spazio
a scapito ovviamente dell‟interoperabilità. Per ottenere tale serializzazione basta
impostare 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 il
metodo 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 metodo
Merge
• caricando i dati attraverso un DataReader tramite il nuovo metodo
DataSet.Load:
Load(DataReader [, load-option] [, tables-array])
utilizzando l‟enumeratore 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 l‟inserimento di
ogni riga viene invocato automaticamente l‟AcceptChanges; se si desidera modificare tale
comportament bisogna settare la proprietà AcceptChangesDuringFill.
Il metodo Fill() può anche essere utilizzato per effettuare il refresh delle tuple: infatti se si
caricano righe con primary key già presenti del DataSet, quest‟ultime verranno sostituite.
• DataSet.Merge(): permette combinare le righe di due DataSet diversi. Le righe del
DataSet di lettura vengono inserite nelle tabelle (con lo steso nome) del primo,
sostituendo eventualmente quelle con lo stesso primary key. Nel caso si voglia un
comportamento diverso bisogna settare il parametro PreserveChange. Al termine delle
operazioni 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 DataSet
usando 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 enumeratore
LoadOption. Nel caso di Fill() è utilizzato settando il parametro FillLoadOption del
DataAdapter, 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 OverwriteRow
Existing Row (the default value)
Added Current = Existing Current = Incoming Current = Incoming
Original = Incoming Original = Existing Original = Incoming
RowState = Modified RowState = Added RowState = Unchanged
Modified Current = Existing Current = Incoming Current = Incoming
Original = Incoming Original = Existing Original = Incoming
RowState = Modified RowState = Modified RowState = Unchanged
Deleted Current = Existing * Undo Delete * Undo Delete
Original = Incoming Current = Incoming Current = Incoming
RowState = Deleted Original = Existing Original = Incoming
RowState = Modified RowState = Unchanged
Unchanged Current = Incoming Current = Incoming Current = Incoming
Original = Incoming Original = Existing Original = Incoming
RowState = Unchanged * if new value = existing RowState = Unchanged
value:
RowState = Unchanged
* else:
RowState = Modified
No matching Current = Incoming Current = Incoming Current = Incoming
existing row in Original = Incoming Original = Existing Original = Incoming
the table RowState = Unchanged RowState = Added RowState = Unchanged
54. ADO.NET 2.0: Altre nuove feautures
Ado.Net 1.x non prevedeva la possibilità di settare manualmente lo stato delle righe:
lo stato era aggiornato automaticamente in base alle operazione effettuate. Questo
poteva rendere difficile l‟aggiornamento di specifiche righe perché l‟Update non era
condizionabile.
Ado.Net 2 introduce due metodi relativi ai DataRow:
•DataRow.SetAdded
•DataRow.SetModified
proprio per variarne lo stato.
Ado.Net 2 introduce inoltre la classe DataTableReader in grado di convertire i dati
contenuti in un DataSet in uno stream, utile per passare un DataSet ad una clase
che accetta un DataReaeder. Va evidenziato che è possibile specificare quali tabelle
esportare.
Per ottenere un DataTableReadere è possibile invocare DataSet.GetDataReader().
55. ADO.NET 2.0: Altre nuove feautures
Ado.Net 2 ha reso indipendente il DataTable. Praticamente è possibile effettuare con esso
tutte le operazioni previste per il DataSet:
ReadXml, ReadXmlSchema, WriteXml, WriteXmlSchema, Clear, Clone, Copy, Merge,
GetChanges
supportando direttamente la serializzazione (implementando l‟interfaccia IXmlSerializable) e
permettendo quindi di restituirne un‟istanza mediante WebServices o Remoting.
Capite bene che inviare su rete un singolo DataTable è molto più conveniente che un intero
DataSet!
Ovviamente per essere totalmente indipendente deve essere possibile popolare direttamente
un DataTable. Ecco quindi il motivo dell‟implementazione dei metodi del DataAdapter che
supportino 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 Asincroni
ADO.NET 2 introduce il modello di esecuzione asincrona (similare all‟APM del
framework .net 2) che riduce i tempi di latenza delle web/windows aplpication
durante le operazioni sui dati, permettendo l‟esecuzione concorrente di molteplici
query.
Seguendo proprio l’APM Model i metodi sono del tipo: BeginXXX ed EndXXX, ad
esempio:
• BeginExecuteReader e EndExecuteReader;
• BeginExecuteNonQuery e EndExecuteNonQuery
così è possibile utilizzare le tecniche di Polling, Wait e Callback per eseguire
operazioni in attesa del completamento del metodo BeginXXX.
Per poter utilizzare il modello asincrono bisogna aggiungere "async=true" alla
Connection String ed evitare di utilzzare i Multiple Active Results Sets (di cui
parleremo dopo).
57. ADO.NET 2.0: Esecuzione Asincrona
Application
Rowset 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
Database1
Data 1
Data 1
Data 1
Data 1
Data 1
Data 1
Data 1
Data 1
Data 1
Data 1
Data 1
Data 1
Connection Latency 3 secs
Data 1 Data 1 Data 1 Data 1
Rowset 2
Data 1 Data 1 Data 1 Data 1
Data 1
Data 1
Data 1
Data 1
Data 1
Data 1
Data 1
Data 1
Database2
Data 1
Data 1
Data 1
Data 1
Data 1
Data 1
Data 1
Data 1
Data 1
Data 1
Data 1
Data 1
Connection Latency 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 1
Data 1
Data 1
Data 1
Data 1
Data 1
Data 1
Data 1
Data 1
Data 1
Database3
Data 1
Data 1
Data 1
Data 1
Data 1
Data 1
Data 1
Data 1 Connection Latency 5 secs
Data 1 Data 1 Data 1 Data 1
Tempo per visualizzare i dati: ~ 3 secs
16
11 secs
Nel caso di esecuzione sincrona, ogni connection deve attendere il termine della
precedente per poter ritornare i dati e quindi per permette all‟applicazione di
visualizzarli.
Risultato: il tempo totale è la somma (teorica) dei tempi necessari alle tre connection
58. ADO.NET 2.0: Esecuzione Asincrona
Application
Rowset 1
Data 1
Data 1
Data 1
Data 1
Data 1
Data 1
Data 1
Data 1
Database1
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 Latency 3 secs
Data 1 Data 1 Data 1 Data 1
Data 1 Data 1 Data 1 Data 1
Rowset 2
Data 1
Data 1
Data 1
Data 1
Data 1
Data 1
Data 1
Data 1
Database2
Data 1
Data 1
Data 1
Data 1
Data 1
Data 1
Data 1
Data 1
Data 1
Data 1
Data 1
Data 1
Connection2 Latency 8 secs
Data 1 Data 1 Data 1 Data 1
Data 1 Data 1 Data 1 Data 1
Rowset 3
Data 1
Data 1
Data 1
Data 1
Data 1
Data 1
Data 1
Data 1 Database3
Data 1
Data 1
Data 1
Data 1
Data 1
Data 1
Data 1
Data 1 Connection3
Data 1
Data 1
Data 1
Data 1
Data 1
Data 1
Data 1
Data 1
Latency 5 secs
Data 1 Data 1 Data 1 Data 1
~ 8 secs
Nel caso di esecuzione asincrona, le connection vengono avviate
contemporaneamente e ritorna appena terminano la propria attività, indipendemente
dalle altre (nell‟esempio la terza connection ritorna dopo 5sec invece che dei 16
precedenti).
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 altre
operazioni 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 dell‟escuzione:
While Not result.IsCompleted
„Codice da eseguire
End While
•Recupera 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
dall‟operazione 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 i
dati prima di poter fare qualcosa) ed analogomante per generare l‟output da un Web
Services.
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 comandi
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
per catturare eventuali timeout, il Case deve contenere una clausola
“case WaitHandle.WaitTimeout”
Questo modello è ideale per le Windows Application perché permette di visualizzare
(utilizzare) i dati appena diventano disponibili senza aspettare il risultato di tutte le
query. Inoltre grazie al metodo Load del DataSet è possibile usare immediatamente
ogni singolo dataReader per caricare una tabella nel DataSet stesso.
62. ADO.NET 2.0: Design Approaches (4)
Callback Model
• Avviare l‟esecuzione, specificando la funzione di callback (delegato) ed il
Command 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 Sub
Si tratta probabilmente dell‟approccio migliore perché lascia al runtime la gestione
completa della chiamata asincrona e l‟incovazione auomatica di un metodo che
esegua le opportune operazioni su dati ottenuti.
Il tutto mentre l‟applicativo continua la sua “normale” esecuzione.
63. ADO.NET 2.0: Design Approaches (5)
Per ognuno degli approcci presentati bisogna applicare una gestione apposita delle
Eccezioni e dei TimeOut.
•Per il WaitOne e WaitAll è preferibile usare sempre il try/catch per ogni metodo
EndXXX
•Per il WaitAny il return value è uguale al tempo di TimeOut
•Per 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ù “update”
query su una Connection provoca la suddetta eccezione.
In ADO.NET 2 (con le Connection relative a SQL Server 2005) è possibile invece
aprire più results set sulla stessa Connection ed eseguire comandi multipli di
modifica sui dati
In sintesi:
• 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
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 childReader
Command2.Parameters("@id").Value = parentReader("id")
Dim childReader As DataReader = Command2.ExecuteReader()
' processa il nuovo childReader
childReader.Close()
End While
parentReader.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 la
riga successiva.
68. DataBinding.: Cos’è il Databinding? (1)
Databinding letteralmente significa “legame” ed è l‟attività 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 al
controllo e successivamente li riassegnamo alla sorgente dati.
Il binding con DataSource 'poveri' implica l'uso 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
BindingManag
erBase
Sync
Data
BindingManag
erBase
70. DataBinding:Il Binding Manager
Il Binding Manager è l'intermediario 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)
BindingManagerBase
Sync
Data
BindingManagerBase
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)
CurrencyManager
BindingContext oppure
PropertyManager
BindingManagerBase
BindingManagerBase DataSource Data
Simple Binding
DataMember
Bindings Binding
Control
BindingsCollection Binding
oppure PropertyName
ControlBindingsCollection Binding
BindingContext Complex Binding
BindingManagerBase
Data
DataSource
Simple Binding
DataMember
Binding
Control
PropertyName
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 aggiornare
Proprietà DataMember
controllo DataSource
int i=5;
myLabel.DataBindings.Add("Text", i, null);
se è null viene usato
ToString()
Il binding con un singolo elemento implica l'uso di PropertyManager
La proprietà Position sarà sempre 0
Il binding con una lista di elementi implica l'uso 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 l'elemento nella lista sottostante (datasource)
75. DataBinding: Simple Binding, format and parse
La classe binding (disponibile solo nel simple binding) offre due eventi
importanti:
• format. Intercetta il dato proveniente dal DataSource prima che venga
impostato nel controllo.
• parse. Intercetta il dato che dal controllo sta per essere trasferito al
DataSource
Catturare e gestire questi eventi permette dimigliorare la qualità della
visualizzazione 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.
DataSource
DataMember
IList IListSource.GetList()
DataSet {
return this.DefaultView;
}
DataTable DataView
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 BindingContext
•il designer usa la convenzione in alto
Quando si usa il CurrencyManager, può essere necessario usare il suo metodo
Refresh affinché il controllo venga aggiornato.
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: Conclusioni
ADO.NET 2 è un framework complesso che permette di lavorare in modo
efficiente ed efficace con la grande maggioranza delle fonti dati oggi
disponibili.
L‟infrastruttura permette agli Sviluppatori di concentrasi sulle questioni di
business evitando di scrivere codice ridondante e perdere intere giornate in
attività di debugging.