ADO .NET Primer Andrea Saltarello Software Architect – Managed Designs S.r.l. http://blogs.ugidotnet.org/pape Sponsor Struttura di ADO .NET ADO .NET è composto da: – Namespace System.Data: racchiude le primitive indipendenti dalla tipologia di base dati. • Sono tutte disconnesse – .NET Managed Provider: implementano le primitive necessarie all’accesso a specifiche basi dati • System.Data.SqlClient per l’accesso a SQL Server 7+ • System.Data.OleDb per connettersi usando un OleDb Provider • System.Data.OracleClient • System.Data.Odbc .NET Data Providers Implementano un insieme comune di interfacce esponendo le classi: – Connection: permette la connessione ad una base dati – Command: permette l’esecuzione di comandi SQL e Stored Procedure – DataReader: implementa un cursore forwardonly, read-only, client side – DataAdapter: permette di “riempire” un contenitore disconnesso Classe Connection Simile ad ADO old-style La Connection String: – Può essere specificata mediante un costruttore parametrico – Utilizza le stesse keyword di ADODB – Richiede attenzione nella specifica del Provider: • SqlClient non lo accetta • System.Data.OleDb non supporta ODBC Dim conSQL As New SqlConnection( ) conSQL.ConnectionString = "Integrated Security=True;" & _ "Data Source=LocalHost;Initial Catalog=Pubs;" conSQL.Open( ) Classe Command Possiamo creare un comando: – Mediante il costruttore – Mediante metodo CreateCommand Possiamo eseguire un comando mediante i metodi: – ExecuteReader: restituisce il DataReader in base ad una query – ExecuteScalar: è il metodo preferibile se il risultato è un singleton – ExecuteNonQuery: esegue un comando di azione Dim commSQL As New SqlCommand( ) commSQL.Connection = conSQL commSQL.CommandText = "Select Count(*) from Authors" MessageBox.Show(commSQL.ExecuteScalar( ).ToString) Invocare Stored Procedure 1. Creare un oggetto Command 2. Impostare CommandType al valore StoredProcedure 3. Impostare la proprietà CommandText 4. Usare il metodo Add per creare e aggiungere parametri 5. Impostare la proprietà ParameterDirection 6. Invocare ExecuteReader 7. Consumare i record, e chiudere il DataReader 8. Leggere i parametri di output e il valore di ritorno Invocare Stored Procedure: un esempio Usare un DataReader Per usare un DataReader, possiamo: – Avanzare alla posizione successiva mediante il metodo Read(), che ritorna True finchè non si sono consumati tutti i dati – Leggere i valori dei campi mediante la proprietà Item, oppure mediante i metodi GetXYZ() Un DataReader impegna la propria connessione, quindi: – Non è possibile utilizzarla per eseguire comandi – Dobbiamo ricordarci di chiuderlo mediante il metodo Close() Usare un DataReader: un esempio Dim commSQL As New SqlClient.SqlCommand( ) commSQL.Connection = conSQL commSQL.CommandText ="Select au_lname,au_fname from authors" Dim datRead As SqlClient.SqlDataReader datRead = commSQL.ExecuteReader( ) Do Until datRead.Read = False MessageBox.Show(datRead.GetString(1) & " " _ & datRead.GetString(0)) Loop datRead.Close( ) DataReader La classe DataSet • E’ un contenitore disconnesso • E’ assimilabile ad un “vettore di matrici” • Permette di specificare vincoli e relazioni tra i dati contenuti • E’ accessibile in scrittura • Permette di propagare le modifiche su un DB • Supporta nativamente la (de)serializzazione in formato XML La classe DataSet DataSet Tables Relations Oggetto Table Collezione Columns Column Constraints Constraint Rows Row Relation Popolare un DataSet • Popolare un DataSet accedendo ad un RDBMS Dim adaptSQL As New SqlClient.SqlDataAdapter( _ "Select * from authors", conSQL) Dim datPubs As DataSet = New DataSet( ) adaptSQL.Fill(datPubs, "NewTable") • Creare un DataSet in via programmatica Dim datPubs As New DataSet( ) Dim tblAuthors As DataTable = New DataTable("authors") tblAuthors.Columns.Add("AuthorID", System.Type.GetType _ ("System.Int32")) La classe DataAdapter • E’ il collegamento tra il “mondo” connesso e quello disconnesso • Può “riempire” un dataSet avvalendosi di una connessione chiusa Dim adaptSQL As New SqlClient.SqlDataAdapter( _ "Select * from authors", conSQL) Dim datPubs As New DataSet( ) adaptSQL.Fill(datPubs, "miaTabella") ' Accesso ai dati adaptSQL.Update (datPubs, "miaTabella") DataSet multi Tabella • Creare la prima tabella Dim mySqlDataAdapter As New SqlDataAdapter( "select * from customers", mySqlConnection) Dim myDataSet As New DataSet() mySqlDataAdapter.Fill(myDataSet, "Customers") • Creare le tabelle successive mySqlDataAdapter.SelectCommand.CommandText = "select * from orders" mySqlDataAdapter.Fill(myDataSet,"Orders") Customers DataSet: Orders Data Tables La classe DataTable Ogni elemento della proprietà Tables è una istanza della classe DataTable La classe 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 Usare una DataTable: un esempio 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 DataSet DataSet: le Relazioni • La classe DataSet espone la proprietà Relations, che è una collezione di istanze della classe DataRelation • Un oggetto DataRelation: – Definisce una associazione tra le colonne di differenti DataTable – definisce una associazione orientata alla navigazione sui dati – NON costituisce una constraint Usare le Relazioni con i DataSet • Creare relazioni 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") Usare Constraint Il supporto alle constraint della classe DataSet permette di: – Creare constraint • Classe ForeignKeyConstraints • Classe 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") Integrità Referenziale Una constraint ForeignKeyConstraint: – permette l’integrità referenziale • Se la proprietà EnforceConstraints del DataSet è impostata a True – Determina le azioni effettuate nelle tabelle correlate • 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. DataRelation Modificare i Dati • Aggiungere righe Dim drNewRow As DataRow = datPubs.Tables("Titles").NewRow 'Populate columns 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) Aggiornare il database • 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") Links http://www.ugidotnet.org http://forum.ugidotnet.org http://mobile.ugidotnet.org