METODOLOGIE di ‘Accesso ai dati’ La gestione dei dati organizzati in archivi risulta più facile ed efficace attraverso l'utilizzo dei database o basi di dati. Nei database gli archivi sono rappresentati da tabelle formate da righe e colonne: le righe corrispondono ai record dell'archivio e le colonne ai campi del record. I prodotti software per la gestione dei database, detti DBMS (Data Base Management System), per esempio Access per Windows, semplificano l'attività dell'utente nelle operazioni di inserimento, modifica e cancellazione dei dati, attraverso l'uso di interfacce grafiche amichevoli; inoltre i dati possono essere ritrovati facilmente con le interrogazioni ai database (query) senza dover specificare i percorsi, le modalità di accesso e le operazioni. La gestione di un database creato con Access (file con estensione .mdb), o con altri prodotti software per la gestione dei database, in ambiente Visual Basic, e non solo, è resa possibile attraverso l’uso di apposite librerie di oggetti e specifici meccanismi di collegamento dei programmi applicativi ai database. Vediamo, in ordine cronologico, le metodologie più utilizzate. ODBC I DBMS hanno, solitamente, un formato proprietario per la memorizzazione e l'acceso dei dati: è necessario utilizzare driver e funzioni specifici per ciascun tipo di database. È, tuttavia, possibile accedere ai dati memorizzati in database di tipo diverso (Access, SQL Server, Oracle ecc.) usando una collezione di funzioni (API – Application Programmino Interface) nota con il nome di Open Database Connectivity (ODBC). Questo è uno standard, sviluppato da Microsoft nel 1992, che fornisce istruzioni e funzioni per l’accesso ai dati memorizzati nei differenti tipi di database e che possono essere richiamate da programmi scritti in vari linguaggi di programmazione (Java, C++, Visual Basic, VBA ecc.). Sono disponibili librerie ODBC (i cosiddetti ODBC driver) per quasi tutti i tipi di database. ODBC permette di connettersi a un database locale o remoto. Microsoft ha creato questa tecnologia per fornire un mezzo con cui sia possibile accedere a molti database diversi (quali dBASE, Microsoft FoxPro, Microsoft Access, Microsoft SQL Server, Oracle e persino file di testo delimitati da virgole) mediante una modalità unica (uso di API comuni). Il computer sul quale viene eseguita l'applicazione si connette a una DLL (Dynamically Linked Library), chiamata ODBC Driver Manager, che invia i comandi a (e recupera i dati da) un driver ODBC specifico per il particolare database che si desidera usare. La sfida di ODBC, quindi, consiste nel fornire un'interfaccia comune a tutti questi diversi database. In teoria potete creare un'applicazione che utilizza ODBC per accedere a un database di Access e poi adattarla a un database di SQL Server cambiando semplicemente il driver ODBC sottostante ed, eventualmente, alcune istruzioni nel codice sorgente. Ciò è possibile in quanto tutti i comandi inviati al database sono istruzioni SQL standard. In pratica il driver ODBC tenta di convertire al meglio i comandi SQL standard nel "dialetto SQL" del particolare database. ODBC è efficiente, almeno in confronto a molte altre tecniche di accesso ai dati. Usare ODBC, tuttavia non è semplice, specialmente per i programmatori Visual Basic. L'insieme delle funzioni di ODBC è molto complesso e, se si commette un errore, spesso l'applicazione termina con un errore fatale. Per questo motivo pochi programmatori Visual Basic scrivono applicazioni che chiamano direttamente le funzioni ODBC. Sono disponibili altre tecniche di accesso ai dati che possono usare i driver ODBC come strati intermedi e che permettono comunque di eseguire chiamate API dirette. Anche se non si utilizzeranno direttamente le chiamate all'API di ODBC nei programmi Visual Basic, è utile conoscere alcuni concetti di base sui quali si fonda questa tecnologia. Un concetto con il quale probabilmente si ha a che fare anche lavorando con ADO è il DSN (Data Source Name o nome di origine dati). Un DSN è un insieme di valori di cui un'applicazione ha bisogno per connettersi correttamente a un database. Un DSN tipicamente include il nome del driver ODBC che desiderate usare, il nome della macchina che ospita il database server (se lavorate con motori client-server quali SQL Server o Oracle), il nome o il percorso dello specifico database, il timeout della connessione (cioè il numero di secondi dopo i quali, durante un tentativo di connessione, il driver ODBC abbandona e restituisce un errore all’applicazione chiamante), i1 nome della workstation e dell'applicazione chiamante e cosi via. E’ possibile creare un DSN in molti modi, all'interno o all'esterno dell'ambiente Visual Basic 6. Un'applet di Control Panel (Pannello di controllo) permette di creare DSN e impostare altri valori di configurazione ODBC. Potete scegliere tra diversi tipi di DSN: un DSN utente è memorizzato nel Registry di sistema, può essere usato solo dall’utente corrente e non può essere condiviso con altri utenti; un DSN di sistema è anch'esso memorizzato nel registro di configurazione ma è visibile a tutti gli altri utenti; un DSN su file è memorizzato in un fìle dsn e può essere condiviso da tutti gli utenti (se il corretto driver ODBC è installato sulle loro macchine). Poichè i DSN su file possono essere facilmente copiati su altre macchine, essi facilitano la fase di installazione; d'altra parte l'applicazione deve sapere dove è posizionato il DSN e quindi il codice deve fornire il percorso completo del file .dsn, che deve essere memorizzato da qualche parte (per esempio in un file INI). I DSN utente e di sistema non presentano questo problema. L'utilizzo dei DSN non è obbligatorio; quando si lavora con ODBC potete fornire direttamente nel vostro codice tutte le informazioni necessarie per la connessione (il nome del driver, il nome e il percorso del database e cosi via); si tratta delle cosiddette connessioni DSN-less (o "senza DSN"), che sono normalmente più efficienti perchè il driver ODBC non deve accedere al Registry di sistema o a un file DSN; le tecniche DSN-less richiedono però un maggiore lavoro da parte dello sviluppatore. OLE DB Da tempo le librerie ODBC non sono più sufficienti per accedere ai database e, per questo motivo, Microsoft, nel 1997, decise di introdurre la nuova interfaccia OLE-DB provider per consentire l'accesso ai dati di qualunque tipo. OLE DB è una tecnologia di accesso ai dati a basso livello con la quale Microsoft ha inteso sostituire ODBC come mezzo principale per la connessione al database. La controparte OLE DB dei driver ODBC sono i provider OLE DB, che costituiscono iI collegamento tra applicazioni e database. Sebbene OLE DB sia una tecnologia relativamente recente, esistono provider OLE DB per la maggior parte dei più diffusi database e altri verranno presto commercializzati. Nonostante l'apparente somiglianza, le tecnologie ODBC e OLE DB sono profondamente diverse: in primo luogo OLE DB il basa su COM (Common Object Model), un'architettura capace di poter gestire grandi quantità di dati in rete; in secondo luogo OLE DB permette di connettersi a qualunque tipo di origine dati; non solo ai database relazionali e ISAM (Indexed Sequentlal Access Mode) che rappresentano il naturale campo di applicazione del driver ODBC. Usando i provider OLE DB si possono elaborare i dati contenuti in messaggi e-mail, pagine HTML, fogli di calcolo, file di testo, ecc. Visual Basic 6 offre provider per Microsoft Jet, SQL Server, FoxPro, file di testo e database Oracle. Altri provider OLE DB possono essere scaricati dal sito Web di Microsoft o acquistati da altri produttori. Nella transizione tra i mondi ODBC e OLE DB potete usare uno speciale provider OLE DB, chiamato MSDASQL, che funziona come un "ponte" verso qualunque origine dati ODBC. Invece di connettervi direttamente al database, potete usare questo speciale provider per connettervi a un driver ODBC, che a sua volta legge e scrive i dati nel database. Questo livello aggiuntivo presenta naturalmente un costo in termini di prestazioni; ma potreste considerarlo come una soluzione di breve periodo per un problema che scomparirà quando saranno disponibili più provider. ADO OLE DB è un'interfaccia di basso livello a cui i linguaggi di alto livello come Visual Basic non possono accedere, o almeno non possono farlo con facilità. Inoltre, per utilizzare le librerie fornite dall'interfaccia OLEDB si possono usare solo alcuni linguaggi di programmazione, tra cui C++, Visual Basic. Per ovviare a questa limitazione, Microsoft ha introdotto un ulteriore strato software denominato ActiveX Data Objects (ADO) che permette di utilizzare anche altri linguaggi di programmazione più semplici. ADO, quindi, è l'Interfaccia di alto livello per OLE DB; si basa su OLE DB ma fornisce funzioni che non sono direttamente disponibili in OLE DB o che richiederebbero la scrittura di codice particolarmente sofisticato. ADO permette di eseguire query e connessioni asincrone oltre che aggiornamenti batch. ADO, rispetto ad altri oggetti precedenti, aggiunge nuove funzionalità, quali Recordset basati su file, Recordset gerarchici e cosi via. ADO nasce per fornire un meccanismo universale di accesso ai dati grazie a una gerarchia di oggetti (ADO object model) che possono essere manipolati all'interno dei programmi scritti nel linguaggio di programmazione preferito. ADO consiste di pochi oggetti che possono essere combinati in molti modi. Un'altra importante caratteristica di ADO è la possibilità di utilizzare questa tecnologia dall'interno delle pagine HTML oppure all'Interno di una pagina ASP (Active Server Page), ospitata su Internet Information Server in esecuzione su un server. Visual Basic include molti strumenti e programmi di utilità per creare applicazioni ADO in modo veloce ed efficiente. Esso consente, tra l’altro, di accedere alle tabelle di un database attraverso l’oggetto visuale Adodc della Casella degli strumenti. Per consentire l'accesso ai dati contenuti nelle tabelle di un database, occorre effettuare alcune impostazioni preliminari di connessione ai dati. APPLICAZIONE La figura a lato riepiloga i diversi metodi di accesso alle origini dati in Visual Basic 6; come si può vedere i vari metodi differiscono notevolmente nel numero di livelli che esistono tra l'applicazione e il database al quale si connette. La nostra attenzione sarà concentrata sulla tecnologia ADO, perché le altre tecnologie saranno nel tempo sostituite da ADO. Altri Controlli Controllo ADO (Adodc 6.0) ADO 2.x - Libreria ODBC Driver Manager (SQL Standard) “Kagera” Driver ODBC specifico Provider OLE DB DATABASE La seguente tabella riporta, in sintesi, alcuni esempi di modalità di connessione ad un database. 1 caso Elementi utilizzati Controllo ADODC ADO 6.0 “Kagera” ODBC Specifico Codice per la connessione Si inderisce l’oggetto adodc sul form adodc1.ConnectionString = "DSN=nome DSN" adodc1.CommandType = adCmdTable|adCmdUnknown adodc1.RecordSource = "nomeatbella|query" Set Text1.DataSource = adodc1 ‘ binding dei dati 2 caso (connessione con DSN) Controllo ADODC ADO 6.0 Provider OLE DB Text1.DataField = “nomecampo” Si inderisce l’oggetto adodc sul form adodc1.ConnectionString = "PROVIDER=Microsoft.Jet.OLEDB.4.0;” _ “DATA SOURCE=percorso file.MDB" adodc1.CommandType = adCmdTable|adCmdUnknown (senza DSN) adodc1.RecordSource = "nomeatbella|query" Set Text1.DataSource = adodc1 ‘ binding dei dati 3 caso ADO non visuale “Kagera” ODBC Specifico (con DSN) Text1.DataField = “nomecampo” ‘Dichiarazioni generali Dim ado1 As ADODB.Connection Dim rs1 As ADODB.Recordset Private Sub Form_Load() Set ado1 = New ADODB.Connection Ado1.Open "DSN=nomeDSN" Set rs1 = New ADODB.Recordset Rs1.Open "tabella|query", ado1, adOpenStatic, adLockOptimistic Visualizza End Sub Private Sub Visualizza() ‘ per ogni text o label: Text1.Text = rs1!nomecampo oppure Text1.Text = rs1(“nomecampo”) End Sub 4 caso ADO non visuale Provider OLE DB Private Sub Salva() ‘ per ogni text o label: rs1!nomecampo = Text1.Text oppure rs1(“nomecampo”) = Text1.Text End Sub ‘Dichiarazioni generali Dim ado1 As ADODB.Connection Dim rs1 As ADODB.Recordset (senza DSN) Private Sub Form_Load() Set ado1 = New ADODB.Connection Ado1.Open = "PROVIDER=Microsoft.Jet.OLEDB.4.0;” _ “DATA SOURCE=percorso file.MDB" Set rs1 = New ADODB.Recordset Rs1.Open "tabella|query", ado1, adOpenStatic, adLockOptimistic Visualizza End Sub Private Sub Visualizza() ‘ per ogni text o label: Text1.Text = rs1!nomecampo oppure Text1.Text = rs1(“nomecampo”) End Sub Private Sub Salva() ‘ per ogni text o label: rs1!nomecampo = Text1.Text oppure rs1(“nomecampo”) = Text1.Text End Sub La creazione del “DSN” La procedura per creare una sorgente di dati (DSN) è descritta nei seguenti passaggi: 1. Dal menu Start|Impostazioni|Pannello di Controllo, scegliere Strumenti di amministrazione e poi Origine dati (ODBC): si apre la finestra di dialogo ODBC Data Source Administrator 2. Selezionare la scheda User DSN, System DSN o File DSN a seconda del tipo di DSN da creare e cliccare su Aggiungi 3. Nella successiva finestra di dialogo, scegliere il Driver in base al tipo di Database da utilizzare (nel nostro caso: Microsoft Access Driver) e cliccare su Fine 4. Nell’ultima finestra di dialogo che si apre (Configurazione ODBC per Microsoft Access) (diversa per ogni tipo di database), inserire il Nome Origine Dati e, tramite il pulsante Seleziona, selezionare cartella e file .mdb contenente il database di Access e fare click su OK La nuova sorgente dati (DSN) viene aggiunta alle altre DSN. L’oggetto ADODC L'ambiente Visual Basic consente di accedere con facilità alle tabelle di database creato con Access (file con estensione .mdb), o con altri prodotti software per la gestione dei database, attraverso il controllo ADODC. Questo controllo non fa parte degli oggetti standard, per cui non è automaticamente presente nella casella degli strumenti e quindi è necessario aggiungerlo; attraverso il menu di Visual Basic Progetto|Componenti (vedi figura a lato), selezionare Microsoft ADO Data Control 6.0 (OLEDB), spuntando la casella corrispondente, e cliccare sul pulsante Applica: a questo punto sulla casella degli strumenti comparirà l’oggetto Adodc. Nel form occorre inserire tanti controlli di tipo Adodc quante sono le tabelle che si vogliono utilizzare nel form. Le informazioni principali da fornire a ciascun adodc sono: Il database da utilizzare (proprietà ConnectionString, che indica tutte le informazioni per l’individuazione del file di Access (avente estensione .mdb) (come ad esempio il DSN) (Tipo dato: oggetto Adodc); La modalità di determinazione dell’insieme di record o RecordSet (proprietà CommandType): Tabella, Query o Stored Procedure (adCmdTable, adCmdText, adCmdStoredProc o adCmdUnknown) (Tipo dato: Numerico).; il nome della tabella contenuta nel database (proprietà RecordSource). Può essere il nome di una tabella (adCmdTable) o di una Query (adCmdText) (Tipo dato: Stringa). Dopo aver assegnato il corretto valore alla proprietà ConnectionString, in fase di progettazione, in corrispondenza della scelta della proprietà RecordSource, si può trovare l'elenco delle tabelle contenute nel database tra le quali è possibile effettuare la scelta. Il RecordSource può anche essere il nome di una query già esistente nel database. Per ricordare all'utente il nome dell'archivio sul quale si intende operare, si può far comparire un nome significativo per la tabella, assegnando un valore alla proprietà Caption del controllo Adodc. Se vogliamo inserire|modificare|cancellare|visualizzare dati in alcuni campi della tabella, inseriamo nel form alcune caselle di testo e/o etichette e associamo a ciascuna di esse il campo corrispondente della tabella. Questa operazione è chiamata Binding e gli oggetti che lo permettono sono detti di tipo DataBound o Data-Aware. Le proprietà da specificare per ciascuna delle caselle di testo sono: • proprietà DataSource, che indica il controllo Adodc a cui il campo si riferisce (si può scegliere tra l'elenco proposto) • proprietà DataField, che indica il campo da associare alla casella di testo o etichetta (dopo aver definito la proprietà DataSource; si può scegliere nell'elenco dei campi proposto. È anche opportuno, per migliorare l'interfaccia grafica per l'utente, inserire una label di intestazione per il form e le label vicino alle caselle di testo o etichette collegate al database per ricordare il significato dei campi corrispondenti. Nel caso si vogliano prelevare dati da una tabella ed inserirli in una tabella collegata (associazione 1 a Molti), è possibile inserire sul form un tipo di casella combinata: controllo DataCombo. Anche questo controllo non è tra quelli standard, per cui è necessario aggiungerlo alla stessa maniera dell’oggetto Adodc, tramite il menu Progetto|Componenti, scegliendo poi l’oggetto Microsoft Data Bound List Controls 6.0. Facendo riferimento all’esempio a lato, vediamo quali sono tutte le proprietà fondamentali dell’oggetto: • proprietà DataSource, che indica il controllo Adodc a cui il campo si riferisce (si può scegliere tra l'elenco proposto) (es.: adoVendite) • proprietà DataField, che indica il campo associato alla casella combinata (es.:CodArt, cioè la chiave esterna della tabella dipendente) • proprietà RowSource, che indica il controllo Adodc a cui si riferisce il campo che viene elencato nella lista (si può scegliere tra l'elenco proposto) (es.: adoArticoli) • proprietà ListField, che indica il campo i cui valori vengono elencati nella lista (si può scegliere tra l'elenco proposto) (es.: DescrArticolo) • proprietà BoundColumn, che indica il campo (della tabella principale) i cui valori vengono registrati nel campo della tabella secondariaelencati nella lista (si può scegliere tra l'elenco proposto) (es.: CodArticolo, cioè la chiave primaria della tabella primaria). Tutti i valori delle proprietà degli oggetti presenti sul form possono essere assegnati in fase di progettazione oppure in fase di esecuzione, p.es. nell’evento Load del form contenente gli oggetti Adodc. A questo scopo si riporta un esempio. Private Sub Form_Load() adoVendite.ConnectionString = "DSN=Esempio" adoVendite.CommandType = adCmdTable adoVendite.RecordSource = "Vendite" adoArticolo.ConnectionString = "DSN=Esempio" adoArticoli.CommandType = adCmdTable adoArticoli.RecordSource = "Articoli" SET dcboArticoli.RowSource = adoVendite dcboArticoli.ListField = "DescrArticolo" SET dcboArticoli.DataSource = adoArticoli dcboArticoli.DataField = "CodArt" dcboArticoli.BoundColumn = "CodArticolo" SET txt_Data.DataSource = adoArticoli Txt_Data.DataField = "Data Vendita" SET txt_Prezzo.DataSource = adoArticoli Txt_Prezzo.DataField = "Prezzo" SET txt_Quantita.DataSource = adoArticoli Txt_Quantita.DataField = "Data Vendita" End Sub L’oggetto ADODB E’, possibile utilizzare l’oggetto la tecnologia ADO senza l’utilizzo di controlli visuali come l’Adodc. In tale caso è necessario indicare al progetto VBasic di fare riferimento agli oggetti presenti nella libreria ADO. I passi da effettuare sono i seguenti 1. Creare un riferimento alla libreria DLL Dal menu Progetto, scegliere Riferimenti… Nella finestra di dialogo che appare, selezionare la libreria Microsoft ActiveX data Objects 2.X Library (dove la è un numero che indica la sottoversione); 2. Creazione oggetti di Connessione e Recordset Nel programma creare due oggetti: uno per attivare la connesione al database e l’altro per gestire i dati (tabelle, query, ecc). Per esempio, nelle dichiarazioni generali: ‘Dichiarazioni generali Dim ado1 As ADODB.Connection Dim rs1 As ADODB.Recordset e nell’evento Load del Form: Set ado1 = New ADODB.Connection Set rs1 = New ADODB.Recordset 3. Attivazione della connessione e Apertura del Recordset. Nell’evento Form_Load, p. es.: Ado1.Open = "PROVIDER=Microsoft.Jet.OLEDB.4.0;” _ “DATA SOURCE=percorso file.MDB" Rs1.Open "tabella|query", ado1, adOpenStatic, adLockOptimistic, tipoComando 4. Visualizzare i dati presenti nel record della tabella del database ‘ per ogni text o label: Text1.Text = rs1!nomecampo oppure Text1.Text = rs1(“nomecampo”) 5. Inserire dati nel record della tabella del database ‘ per ogni text o label: rs1!nomecampo = Text1.Text oppure rs1(“nomecampo”) = Text1.Text 6. Chiudere Recordset e Connection Ado1.Close Rs1.Close 7. Distruggere gli oggetti Connection e Recordset Set ado1 = Nothing Set rs1 = Nothing ESEMPIO ‘ Dichiarazioni generali Dim adoSupermercato As ADODB.Connection Dim rsProdotti As ADODB.Recordset Private Sub cmd_Nav_Click(Index As Integer) Select Case Index Case 0 rsProdotti.MoveFirst Case 1 rsProdotti.MovePrevious If rsProdotti.BOF Then rsProdotti.MoveFirst End If Case 2 rsProdotti.MoveNext If rsProdotti.EOF Then rsProdotti.MoveLast End If Case 3 rsProdotti.MoveLast End Select Visualizza End Sub Private Sub Command1_Click(Index As Integer) Ab_Disab1 Select Case Index Case 0 rsProdotti.AddNew txt_CodP = "" txt_DesP = "" txt_Prezzo = "" txt_Giac = "" txt_ScMin = "" Case 1 Case 2 rsProdotti.Delete End Select End Sub Private Sub Command2_Click(Index As Integer) Select Case Index Case 0 ' Prepara il buffer per la registrazione rsProdotti!DesP = txt_DesP rsProdotti!Prezzo = txt_Prezzo rsProdotti!Giacenza = txt_Giac rsProdotti!ScortaMin = txt_ScMin rsProdotti.Update Case 1 rsProdotti.CancelUpdate ' Ripristina i valori precedenti Visualizza 'txt_CodP = rsProdotti!CodProdotto 'txt_DesP = rsProdotti!DesP 'txt_Prezzo = rsProdotti!Prezzo 'txt_Giac = rsProdotti!Giacenza 'txt_ScMin = rsProdotti!ScortaMin End Select Ab_Disab2 End Sub Private Sub Form_Load() Set adoSupermercato = New ADODB.Connection adoSupermercato.Open "DSN=Supermercato" Set rsProdotti = New ADODB.Recordset rsProdotti.Open "SELECT * FROM Prodotti", adoSupermercato, adOpenStatic, adLockOptimistic, adCmdText Visualizza End Sub Private Sub Visualizza() txt_CodP = rsProdotti!CodProdotto txt_DesP = rsProdotti!DesP txt_Prezzo = rsProdotti!Prezzo txt_Giac = rsProdotti!Giacenza txt_ScMin = rsProdotti!ScortaMin End Sub Private Sub Ab_Disab1() For i = 0 To Command1.Count - 1 Command1(i).Enabled = False Next For i = 0 To Command2.Count - 1 Command2(i).Enabled = True Next For i = 0 To cmd_Nav.Count - 1 cmd_Nav(i).Enabled = False Next txt_DesP.Enabled = True txt_Prezzo.Enabled = True txt_Giac.Enabled = True txt_ScMin.Enabled = True End Sub Private Sub Ab_Disab2() For i = 0 To Command1.Count - 1 Command1(i).Enabled = True Next For i = 0 To Command2.Count - 1 Command2(i).Enabled = False Next For i = 0 To cmd_Nav.Count - 1 cmd_Nav(i).Enabled = True Next txt_DesP.Enabled = False txt_Prezzo.Enabled = False txt_Giac.Enabled = False txt_ScMin.Enabled = False End Sub