SlideShare una empresa de Scribd logo
1 de 79
Microsoft ADO.NET


        ActiveX Data Object .NET




Ing. Felice Pescatore
felice.pescatore@poste.it
ADO.NET: Compendi Consigliati




                                                         Autori:
      • msdn2.microsoft.com/it-it/library/default.aspx   •Francesco Balena
      • www.ugidotnet.org                                •Dino Esposito
      • www.aspitalia.com                                •Marco Bellinaso
      • www.dotnet2themax.it                             •David Sheppa
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.
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.
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;
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.
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
ADO.NET: architettura applicativa
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
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.
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
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
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
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
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
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
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
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();
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.
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
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.
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()
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()
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();
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();
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();
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");
   }
 }
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;
        }
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.
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
ADO.NET: Data Set Object Model
                                                                               Collezioni

                                                                                DataSet

                                       DataSet




  DataRelationsCollection                          DataTableCollection




       DataRelation                                     DataTable




 DataTable      DataTable   ConstraintCollection   DataRowCollection DataColumnCollection




DataColumn      DataRow         Constraint             DataRow           DataColumn
ADO.NET: Ruolo del DataAdapter
                                   Select
                                xxxCommand




                              xxxCommandBuilder

   xxxDataAdapter
                                   Insert
                                xxxCommand
                                                  xxxConnection
                                   Update
                                xxxCommand



                                   Delete
                                xxxCommand
                                                    Data
                    DataSet
ADO.NET: Architettura del DataAdapter

                         XxxDataAdapter
    SelectCommand    UpdateCommand   InsertCommand   DeleteCommand


     XxxDataReader


     XxxCommand       XxxCommand     XxxCommand       XxxCommand


                             XxxConnection



       sp_SELECT       sp_UPDATE       sp_INSERT       sp_DELETE
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")
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
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
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
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")
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.
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)
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")
Microsoft: ADO.NET 1.x to 2.0



                  ActiveX Data Object .NET
                   dalla versione 1.x alla 2.0
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.
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.
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
ADO.NET 2.0: insieme dei componenti
                                   DataSource




   TableAdapter               TableAdapter           TableAdapter
                  DataTable              DataTable              DataTable

   DataSet




              BindingSource           BindingSource         BindingSource


     NamedRange ListObject Label         Bookmark TextBox Label
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()
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!
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());
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
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
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.
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
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().
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
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).
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
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.
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.
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.
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.
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.
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
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
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.
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.
ADO.NET Databinding


    ADO.NET & Data Component
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.
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
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
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)
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.
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
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)
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.
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
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
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”;
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.

Más contenido relacionado

Similar a Ado net (versione 1 e 2)

Py a6 python-database
Py a6 python-databasePy a6 python-database
Py a6 python-databaseMajong DevJfu
 
A. Mattiocco - RJSDMX (Connettori SDMX per Software Statistici)
A. Mattiocco - RJSDMX (Connettori SDMX per Software Statistici) A. Mattiocco - RJSDMX (Connettori SDMX per Software Statistici)
A. Mattiocco - RJSDMX (Connettori SDMX per Software Statistici) Istituto nazionale di statistica
 
Entity Framework 4.0 vs NHibernate
Entity Framework 4.0 vs NHibernateEntity Framework 4.0 vs NHibernate
Entity Framework 4.0 vs NHibernateManuel Scapolan
 
WPF & LINQ: VB T&T Community After Hour @ Microsoft Days 08
WPF & LINQ: VB T&T Community After Hour @ Microsoft Days 08WPF & LINQ: VB T&T Community After Hour @ Microsoft Days 08
WPF & LINQ: VB T&T Community After Hour @ Microsoft Days 08Alessandro Del Sole
 
Design Patterns - enterprise patterns (part I)
Design Patterns - enterprise patterns (part I)Design Patterns - enterprise patterns (part I)
Design Patterns - enterprise patterns (part I)Fabio Armani
 
Cassandra DB - Linux Day 2019 - Catania - Italy
Cassandra DB - Linux Day 2019 - Catania - ItalyCassandra DB - Linux Day 2019 - Catania - Italy
Cassandra DB - Linux Day 2019 - Catania - ItalyFabrizio Spataro
 
Design Patterns - Enterprise Patterns (part 2)
Design Patterns - Enterprise Patterns (part 2)Design Patterns - Enterprise Patterns (part 2)
Design Patterns - Enterprise Patterns (part 2)Fabio Armani
 
SQLite in Xamarin.Forms
SQLite in Xamarin.FormsSQLite in Xamarin.Forms
SQLite in Xamarin.FormsGuido Magrin
 

Similar a Ado net (versione 1 e 2) (20)

Excel development e sql 2.1
Excel development e sql   2.1Excel development e sql   2.1
Excel development e sql 2.1
 
Office & VBA - Giorno 6
Office & VBA - Giorno 6Office & VBA - Giorno 6
Office & VBA - Giorno 6
 
Dot net framework 2
Dot net framework 2Dot net framework 2
Dot net framework 2
 
Py a6 python-database
Py a6 python-databasePy a6 python-database
Py a6 python-database
 
A. Mattiocco - RJSDMX (Connettori SDMX per Software Statistici)
A. Mattiocco - RJSDMX (Connettori SDMX per Software Statistici) A. Mattiocco - RJSDMX (Connettori SDMX per Software Statistici)
A. Mattiocco - RJSDMX (Connettori SDMX per Software Statistici)
 
Entity Framework 4.0 vs NHibernate
Entity Framework 4.0 vs NHibernateEntity Framework 4.0 vs NHibernate
Entity Framework 4.0 vs NHibernate
 
Data flow
Data flowData flow
Data flow
 
Wcf data services
Wcf data servicesWcf data services
Wcf data services
 
WPF & LINQ: VB T&T Community After Hour @ Microsoft Days 08
WPF & LINQ: VB T&T Community After Hour @ Microsoft Days 08WPF & LINQ: VB T&T Community After Hour @ Microsoft Days 08
WPF & LINQ: VB T&T Community After Hour @ Microsoft Days 08
 
Design Patterns - enterprise patterns (part I)
Design Patterns - enterprise patterns (part I)Design Patterns - enterprise patterns (part I)
Design Patterns - enterprise patterns (part I)
 
Corso web services
Corso web servicesCorso web services
Corso web services
 
Linuxday2013
Linuxday2013 Linuxday2013
Linuxday2013
 
ASP.NET
ASP.NETASP.NET
ASP.NET
 
Dbms
DbmsDbms
Dbms
 
Oracle 1
Oracle 1Oracle 1
Oracle 1
 
Office & VBA - Giorno 7
Office & VBA - Giorno 7Office & VBA - Giorno 7
Office & VBA - Giorno 7
 
Cassandra DB - Linux Day 2019 - Catania - Italy
Cassandra DB - Linux Day 2019 - Catania - ItalyCassandra DB - Linux Day 2019 - Catania - Italy
Cassandra DB - Linux Day 2019 - Catania - Italy
 
Design Patterns - Enterprise Patterns (part 2)
Design Patterns - Enterprise Patterns (part 2)Design Patterns - Enterprise Patterns (part 2)
Design Patterns - Enterprise Patterns (part 2)
 
SQLite in Xamarin.Forms
SQLite in Xamarin.FormsSQLite in Xamarin.Forms
SQLite in Xamarin.Forms
 
ORM - Introduzione
ORM - IntroduzioneORM - Introduzione
ORM - Introduzione
 

Más de Felice Pescatore

Il Cinismo dell'Agilista Imbruttito
Il Cinismo dell'Agilista ImbruttitoIl Cinismo dell'Agilista Imbruttito
Il Cinismo dell'Agilista ImbruttitoFelice Pescatore
 
Intelligent Business Agility
Intelligent Business AgilityIntelligent Business Agility
Intelligent Business AgilityFelice Pescatore
 
Disciplined Agile, la Promessa, la Svolta e il Prestigio
Disciplined Agile, la Promessa, la Svolta e il PrestigioDisciplined Agile, la Promessa, la Svolta e il Prestigio
Disciplined Agile, la Promessa, la Svolta e il PrestigioFelice Pescatore
 
The Disciplined Approach to Change
The Disciplined Approach to ChangeThe Disciplined Approach to Change
The Disciplined Approach to ChangeFelice Pescatore
 
The Disciplined Approach to Change
The Disciplined Approach to ChangeThe Disciplined Approach to Change
The Disciplined Approach to ChangeFelice Pescatore
 
PMI Disciplined Agile: la Promessa, la Svolta e il Prestigio
PMI Disciplined Agile: la Promessa, la Svolta e il PrestigioPMI Disciplined Agile: la Promessa, la Svolta e il Prestigio
PMI Disciplined Agile: la Promessa, la Svolta e il PrestigioFelice Pescatore
 
Un cuore moderno per l'Agilità
Un cuore moderno per l'AgilitàUn cuore moderno per l'Agilità
Un cuore moderno per l'AgilitàFelice Pescatore
 
L'Occhio di Ra sul Testing
L'Occhio di Ra sul TestingL'Occhio di Ra sul Testing
L'Occhio di Ra sul TestingFelice Pescatore
 
Industry 4.0... a che punto siamo in Italia
Industry 4.0... a che punto siamo in ItaliaIndustry 4.0... a che punto siamo in Italia
Industry 4.0... a che punto siamo in ItaliaFelice Pescatore
 
Agile IoT & Eclipse Duttile
Agile IoT & Eclipse DuttileAgile IoT & Eclipse Duttile
Agile IoT & Eclipse DuttileFelice Pescatore
 
Fuffa Day - The Sixth Sense
Fuffa Day - The Sixth SenseFuffa Day - The Sixth Sense
Fuffa Day - The Sixth SenseFelice Pescatore
 
Value Focused Team: road to DevOps
Value Focused Team: road to DevOpsValue Focused Team: road to DevOps
Value Focused Team: road to DevOpsFelice Pescatore
 

Más de Felice Pescatore (20)

Il Cinismo dell'Agilista Imbruttito
Il Cinismo dell'Agilista ImbruttitoIl Cinismo dell'Agilista Imbruttito
Il Cinismo dell'Agilista Imbruttito
 
Intelligent Business Agility
Intelligent Business AgilityIntelligent Business Agility
Intelligent Business Agility
 
AgileBIM, BIM mets Agile
AgileBIM, BIM mets AgileAgileBIM, BIM mets Agile
AgileBIM, BIM mets Agile
 
Disciplined Agile, la Promessa, la Svolta e il Prestigio
Disciplined Agile, la Promessa, la Svolta e il PrestigioDisciplined Agile, la Promessa, la Svolta e il Prestigio
Disciplined Agile, la Promessa, la Svolta e il Prestigio
 
AgileBIM overview
AgileBIM overviewAgileBIM overview
AgileBIM overview
 
The Disciplined Approach to Change
The Disciplined Approach to ChangeThe Disciplined Approach to Change
The Disciplined Approach to Change
 
The Disciplined Approach to Change
The Disciplined Approach to ChangeThe Disciplined Approach to Change
The Disciplined Approach to Change
 
PMI Disciplined Agile: la Promessa, la Svolta e il Prestigio
PMI Disciplined Agile: la Promessa, la Svolta e il PrestigioPMI Disciplined Agile: la Promessa, la Svolta e il Prestigio
PMI Disciplined Agile: la Promessa, la Svolta e il Prestigio
 
Agilozzi le testa tutte
Agilozzi le testa tutteAgilozzi le testa tutte
Agilozzi le testa tutte
 
39bit al secondo
39bit al secondo39bit al secondo
39bit al secondo
 
Un cuore moderno per l'Agilità
Un cuore moderno per l'AgilitàUn cuore moderno per l'Agilità
Un cuore moderno per l'Agilità
 
L'Occhio di Ra sul Testing
L'Occhio di Ra sul TestingL'Occhio di Ra sul Testing
L'Occhio di Ra sul Testing
 
#NoElevator4DevOps
#NoElevator4DevOps#NoElevator4DevOps
#NoElevator4DevOps
 
Don't Dirty my Backlog!
Don't Dirty my Backlog!Don't Dirty my Backlog!
Don't Dirty my Backlog!
 
Industry 4.0... a che punto siamo in Italia
Industry 4.0... a che punto siamo in ItaliaIndustry 4.0... a che punto siamo in Italia
Industry 4.0... a che punto siamo in Italia
 
Agile IoT & Eclipse Duttile
Agile IoT & Eclipse DuttileAgile IoT & Eclipse Duttile
Agile IoT & Eclipse Duttile
 
Fuffa Day - The Sixth Sense
Fuffa Day - The Sixth SenseFuffa Day - The Sixth Sense
Fuffa Day - The Sixth Sense
 
#NoElevator for DevOps
#NoElevator for DevOps#NoElevator for DevOps
#NoElevator for DevOps
 
Value Focused Team
Value Focused TeamValue Focused Team
Value Focused Team
 
Value Focused Team: road to DevOps
Value Focused Team: road to DevOpsValue Focused Team: road to DevOps
Value Focused Team: road to DevOps
 

Ado net (versione 1 e 2)

  • 1. Microsoft ADO.NET ActiveX Data Object .NET Ing. Felice Pescatore felice.pescatore@poste.it
  • 2. ADO.NET: Compendi Consigliati Autori: • msdn2.microsoft.com/it-it/library/default.aspx •Francesco Balena • www.ugidotnet.org •Dino Esposito • www.aspitalia.com •Marco Bellinaso • www.dotnet2themax.it •David Sheppa
  • 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
  • 33. ADO.NET: Architettura del DataAdapter XxxDataAdapter SelectCommand UpdateCommand InsertCommand DeleteCommand XxxDataReader XxxCommand XxxCommand XxxCommand XxxCommand XxxConnection sp_SELECT sp_UPDATE sp_INSERT sp_DELETE
  • 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")
  • 42. Microsoft: ADO.NET 1.x to 2.0 ActiveX Data Object .NET dalla versione 1.x alla 2.0
  • 43. ADO.NET 2.0: evoluzione ADO.NET v1.0/1.1 è basato su alcune interfacce comuni, implementate dai singoli provider. Nonostante la flessibilità che ciò comporta è problematico scrivere codice indipendente dalla base dati. ADO .NET 2.0 è basato su classi base condivise dai provider, e si presenta come 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
  • 46. ADO.NET 2.0: insieme dei componenti DataSource TableAdapter TableAdapter TableAdapter DataTable DataTable DataTable DataSet BindingSource BindingSource BindingSource NamedRange ListObject Label Bookmark TextBox Label
  • 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.
  • 67. ADO.NET Databinding ADO.NET & Data Component
  • 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.