TheTruster's Box

  • Increase font size
  • Default font size
  • Decrease font size
Home Programmazione Articoli Esplorare un Database Access con OpenSchema di ADO in Visual Basic 6

Esplorare un Database Access con OpenSchema di ADO in Visual Basic 6

E-mail Stampa PDF

ADO è uno strumento molto potente per quanto riguarda l'accesso ad un DB, e consente di gestire il trattamento dei dati da/per il DB in maniera piuttosto agevole ed intuitiva con relativamente pochi oggetti e con semplici metodi.

Un aspetto meno conosciuto del modello ad oggetti ADO è la possibilità di "esplorare" il DB anche dal punto di vista strutturale con il metodo OpenSchema. Con questo metodo possiamo andare a sbirciare nell'elenco delle tabelle disponibili in un DB e dei relativi campi.

Non solo questo, in realtà, poichè il metodo che andrò ad illustrare - seppure in minima parte - permette di esplorare molto più delle semplici tabelle e dei campi che le compongono (oltre ad eventuali indici, tipi di campo, chiavi primarie, etc.) in quanto consente di accedere all'intero catalogo delle query o delle procedure e ad altre peculiari caratteristiche riscontrabili normalmente nella struttura di un database.

A questo punto potrebbe anche sollevarsi la questione del "perchè" dovremmo occuparci di andare ad esplorare la struttura di un DB, quando quello che normalmente basta è trattarlo come un cassetto nel quale riporre dati ritirandoli fuori al momento giusto! In realtà (anche se non è una pratica che consiglierei) potrebbe capitare che la struttura di un DB non sia così rigida e che si renda necessario, in corso di utilizzo, l'aggiunta o l'eliminazione dinamica di tabelle o campi. Per non rinunciare alla flessibilità della nostra applicazione non rimane altra strada che far sapere all'applicazione stessa come è fatto il DB.

Per semplicità ci rivolgeremo ad un database Access e, per meglio comprendere il funzionamento del metodo in argomento, realizzeremo una semplice applicazione che, volendo, potrà essere migliorata ed ampliata per dotarla di ulteriori caratteristiche, che le permettano di andare ancora più in profondità nell'esplorazione di un DB.

Questo piccolo tool sarà formato da un singolo Form all'interno del quale troveranno posto alcuni controlli come un TextBox, due ListView, un controllo CommonDialog, un paio di pulsanti e qualche label.

Per usare la ListView e il CommonDialog dovremo referenziare questi controlli nella lista dei Componenti, accessibile dal menu Progetto -> Componenti.



Sarà inoltre necessario referenziare la libreria ADO più recente sul PC. Normalmente dovrebbe essere la Microsoft ActiveX Data Object 2.8 Library


Preparato lo scenario, possiamo procedere alla progettazione del Form.


Iniziamo a scrivere del codice e, nella sezione dichiarazioni del nostro Form, dichiariamo l'oggetto relativo alla connessione che servirà per accedere al DB.

Dim cn As ADODB.Connection

Sfruttando l'evento Form_Load() possiamo occuparci di preparare gli oggetti che raccoglieranno i dati, ovvero le ListView. Aggiungeremo delle colonne in relazione ai dati da visualizzare e contestualmente prepareremo anche il CommonDialog per permetterci di specificare il Database .mdb che esploreremo.

 
Private Sub Form_Load()
 
With lwTables
    .View = lvwReport
    .ColumnHeaders.Add , , "Nome Tabella"
    .ColumnHeaders.Add , , "Tipo Tabella"
End With
 
With lwFields
    .View = lvwReport
    .ColumnHeaders.Add , , "Nome Campo"
    .ColumnHeaders.Add , , "Tipo Campo"
    .ColumnHeaders.Add , , "Lunghezza"
End With
 
With cDialog
    .CancelError = True
    .DefaultExt = "*.mdb"
    .DialogTitle = "Seleziona un Database Access"
    .Filter = "Database Access (*.mdb)|*.mdb"
    .Flags = cdlOFNExplorer Or cdlOFNFileMustExist
End With
 
End Sub
 

Passiamo a scrivere il codice relativo alla pressione sul tasto di caricamento del DB.
La sequenza delle operazioni è piuttosto logica:

  • viene aperto il CommonDialog in modalità di selezione Files
  • una volta ottenuto il nome del file lo si usa per aprire la Connessione dichiarata in precedenza
  • vengono resettate le ListView che accoglieranno i dati
  • si invoca la routine RetrieveTables (che vedremo dettagliatamente in seguito) che serve per popolare la ListView con le tabelle presenti nel DB.

Private Sub cmdLoadDB_Click()
On Error GoTo No_File
 
cDialog.ShowOpen
 
Set cn = New ADODB.Connection
cn.Open "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" & cDialog.FileName
txtDBPath.Text = cDialog.FileName
 
lwTables.ListItems.Clear
lwFields.ListItems.Clear
 
RetrieveTables
 
No_File:
 
End Sub

La Routine RetrieveTables è uno dei tasselli importanti di questa piccola applicazione.
E' qui che viene utilizzato il metodo OpenSchema per accedere alla struttura delle Tabelle del nostro DB. Come dicevo, attraverso OpenSchema è possibile esplorare diversi aspetti della struttura del database e tutto dipende dalla costante passata come argomento al metodo (Schema As SchemaEnum) e dai criteri imposti (Restrictions), che sono opzionali e variano a seconda della costante utilizzata e in base alla necessità di filtrare, in relazione alla nostra esigenza, la lista degli oggetti che vogliamo ottenere.
La sintassi del metodo è la seguente:

OpenSchema (Schema As SchemaEnum, [Restrictions], [SchemaID])

Il metodo restituisce un oggetto di Recordset che conterrà tanti record per quante tabelle verranno trovate.
Per ottenere la lista di tutte le tabelle comprese quelle nascoste "di sistema" utili alle impostazioni del DB è necessario specificare esclusivamente la costante adSchemaTables.

Sub RetrieveTables()
 
Dim itmX As MSComctlLib.ListItem
Dim rsTables As ADODB.Recordset
 
Set rsTables = cn.OpenSchema(adSchemaTables)
If Not (rsTables.BOF And rsTables.EOF) Then    
    While Not rsTables.EOF
        Set itmX = lwTables.ListItems.Add(, , rsTables.Fields("TABLE_NAME").Value)
            itmX.ListSubItems.Add , , rsTables.Fields("TABLE_TYPE").Value
        rsTables.MoveNext
    Wend
End If
rsTables.Close
 
Set rsTables = Nothing
Set itmX = Nothing
 
End Sub

Come si può vedere nella precedente routine sono stati utilizzati esclusivamente 2 campi del recordset contenente la lista delle tabelle, ovvero TABLE_NAME e TABLE_TYPE, ma è possibile sapere molto di più su una tabella, utilizzando il valore contenuto negli altri campi:

TABLE_CATALOG
TABLE_SCHEMA
TABLE_NAME
TABLE_TYPE
TABLE_GUID
DESCRIPTION
TABLE_PROPID
DATE_CREATED
DATE_MODIFIED

Occupiamoci adesso di gestire la seconda ListView che ospiterà la lista dei campi e alcuni dei dati ad essi relativi.

Useremo l'evento ItemClick() per ottenere dall'Item cliccato il nome della tabella da passare al metodo OpenSchema come parametro "Restrictions".

Private Sub lwTables_ItemClick(ByVal Item As MSComctlLib.ListItem)
lwFields.ListItems.Clear
RetrieveFields (Item.Text)
End Sub

Restrictions in realtà può essere un Array contenente diversi parametri dipendenti strettamente dal tipo di oggetto richiesto.
Una lista completa dei parametri relativi ad ogni costante che è possibile passare al metodo OpenSchema la trovate qui:

W3Schools - OpenSchema

Per quello che ci riguarda, ovvero tirar fuori la lista dei campi relativi ad una tabella ci basta questo:

Constant Value Description Constraint
Columns
adSchemaColumns 4 Returns the columns of tables
defined in the catalog
TABLE_CATALOG
TABLE_SCHEMA
TABLE_NAME
COLUMN_NAME

Come dicevo in precedenza Restrictions è facoltativo per cui, se non viene usato, OpenSchema restituirà l'elenco completo di tutti i campi del DB a prescindere dalla tabella in cui essi si trovino.

Ovviamente non è il nostro intento, e considerato che abbiamo a disposizione il nome della tabella della quale intendiamo sapere i campi, è opportuno preparare un Array da passare ad OpenSchema per ottenere quelli presenti nella tabella di nostro interesse.

L'array è presente nella routine seguente e si chiama Criteri. Esso viene valorizzato con 3 parametri dei quali i primi 2 come Empty (ovvero l'elenco dei campi non verrà filtrato nè per TABLE_CATALOG nè per TABLE_SCHEMA) ma contiene, nel terzo parametro, il nome della tabella passato attraverso l'argomento FromTable della Routine. Non è necessario indicare il 4° parametro che verrà valutato anch'esso come Empty:

Sub RetrieveFields(FromTable As String)
 
Dim itmX As MSComctlLib.ListItem
Dim rsFields As ADODB.Recordset
Dim Criteri As Variant
 
Criteri = Array(Empty, Empty, FromTable)
 
Set rsFields = cn.OpenSchema(adSchemaColumns, Criteri)
If Not (rsFields.BOF And rsFields.EOF) Then
    While Not rsFields.EOF
        Set itmX = lwFields.ListItems.Add(, , rsFields.Fields("COLUMN_NAME").Value)
            itmX.ListSubItems.Add , , ConvertTypeCode(rsFields.Fields("DATA_TYPE").Value)
            itmX.ListSubItems.Add , , rsFields.Fields("CHARACTER_MAXIMUM_LENGTH").Value & ""
        rsFields.MoveNext
    Wend
End If
rsFields.Close
 
Set rsFields = Nothing
Set itmX = Nothing
 
End Sub

Analogamente a quanto avviene per la ListView delle tabelle anche per i campi abbiamo ottenuto, oltre ai loro nomi, delle informazioni aggiuntive.
La prima è DATA_TYPE che altro non è che la tipizzazione del campo del DB. Il valore restituito è una costante numerica che effettivamente, a meno di non avere la memoria di Salomone, dice davvero poco sull'effettiva natura del dato presente nel campo. Per ottenere una risposta maggiormente indicativa possiamo realizzare una semplice Function che restituisce una stringa con il nome della costante passata come argomento.

Function ConvertTypeCode(c As Integer) As String
 
Select Case c
 
        Case adDBTimeStamp
            ConvertTypeCode = "adDBTimeStamp"
        Case adArray
            ConvertTypeCode = "adArray"
        Case adBigInt
            ConvertTypeCode = "adBigInt"
        Case adBinary
            ConvertTypeCode = "adBinary"
        Case adSingle
            ConvertTypeCode = "adSingle"
        Case adNumeric
            ConvertTypeCode = "adNumeric"
        Case adLongVarWChar
            ConvertTypeCode = "adLongVarWChar"
        Case adLongVarChar
            ConvertTypeCode = "adLongVarChar"
        Case adLongVarBinary
            ConvertTypeCode = "adLongVarBinary"
        Case adIUnknown
            ConvertTypeCode = "adIUnknown"
        Case adInteger
            ConvertTypeCode = "adInteger"
        Case adIDispatch
            ConvertTypeCode = "adIDispatch"
        Case adGUID
            ConvertTypeCode = "adGUID"
        Case adError
            ConvertTypeCode = "adError"
        Case adEmpty
            ConvertTypeCode = "adEmpty"
        Case adDouble
            ConvertTypeCode = "adDouble"
        Case adDecimal
            ConvertTypeCode = "adDecimal"
        Case adDBTimeStamp
            ConvertTypeCode = "adDBTimeStamp"
        Case adDBTime
            ConvertTypeCode = "adDBTime"
        Case adDBDate
            ConvertTypeCode = "adDBDate"
        Case adDate
            ConvertTypeCode = "adDate"
        Case adCurrency
            ConvertTypeCode = "adCurrency"
        Case adChar
            ConvertTypeCode = "adChar"
        Case adBSTR
            ConvertTypeCode = "adBSTR"
        Case adByRef
            ConvertTypeCode = "adByRef"
        Case adBoolean
            ConvertTypeCode = "adBoolean"
        Case adSmallInt
            ConvertTypeCode = "adSmallInt"
        Case adTinyInt
            ConvertTypeCode = "adTinyInt"
        Case adUnsignedBigInt
            ConvertTypeCode = "adUnsignedBigInt"
        Case adUnsignedInt
            ConvertTypeCode = "adUnsignedInt"
        Case adUnsignedSmallInt
            ConvertTypeCode = "adUnsignedSmallInt"
        Case adUnsignedTinyInt
            ConvertTypeCode = "adUnsignedTinyInt"
        Case adBoolean
            ConvertTypeCode = "adBoolean"
        Case adUserDefined
            ConvertTypeCode = "adUserDefined"
        Case adVarBinary
            ConvertTypeCode = "adVarBinary"
        Case adVarChar
            ConvertTypeCode = "adVarChar"
        Case adVariant
            ConvertTypeCode = "adVariant"
        Case adVector
            ConvertTypeCode = "adVector"
        Case adVarWChar
            ConvertTypeCode = "adVarWChar"
        Case adWChar
            ConvertTypeCode = "adWChar"
End Select
 
End Function

Al posto dei nomi delle costanti è ovviamente possibile farsi restituire dalla Function qualsiasi testo ci aiuti a capire meglio il tipo di contenuto del Campo.

La seconda informazione che intendiamo rilevare dal Campo è la lunghezza massima consentita (valevole per i campi di tipo testo), per cui possiamo analizzare il valore contenuto in CHARACTER_MAXIMUM_LENGTH

Anche in questo caso, come per le Tabelle è possibile sapere molte più informazioni sullo stato di un campo, e basta utilizzare altri nomi di campo, tra quelli qui sotto elencati, disponibili nel Recordset restituito da OpenSchema:

TABLE_CATALOG
TABLE_SCHEMA
TABLE_NAME
COLUMN_NAME
COLUMN_GUID
COLUMN_PROPID
ORDINAL_POSITION
COLUMN_HASDEFAULT
COLUMN_DEFAULT
COLUMN_FLAGS
IS_NULLABLE
DATA_TYPE
TYPE_GUID
CHARACTER_MAXIMUM_LENGTH
CHARACTER_OCTET_LENGTH
NUMERIC_PRECISION
NUMERIC_SCALE
DATETIME_PRECISION
CHARACTER_SET_CATALOG
CHARACTER_SET_SCHEMA
CHARACTER_SET_NAME
COLLATION_CATALOG
COLLATION_SCHEMA
COLLATION_NAME
DOMAIN_CATALOG
DOMAIN_SCHEMA
DOMAIN_NAME
DESCRIPTION

Siamo giunti alla conclusione e la nostra piccola applicazione dovrebbe essere funzionante, eseguendo le operazioni per le quali l'abbiamo creata. Per scoprire se è vero non ci resta che lanciarla con F5 e caricare un DB premendo sul pulsante con i tre puntini [...]


Il risultato non è male e abbiamo appena scalfito la superficie del vasto mondo di OpenSchema, ma la metodologia di base qui illustrata è valevole per l'esplorazione degli ulteriori e talvolta più complessi aspetti di un Database. Una delle caratteristiche che si possono implementare in maniera quasi indolore, ad esempio, è la rilevazione delle Query presenti nel DB (delle quali è possibile sapere anche la frase SQL che le definisce) o ancora le chiavi primarie relative ad una determinata Tabella oppure i suoi Indici... le possibilità sono moltissime.

In area Download -> Progetti potete scaricare il progetto di esempio realizzato per illustrare il metodo OpenSchema.

 

Aggiungi commento

Si prega di aggiungere commenti in tema.
Sono assolutamente vietati messaggi volgari, pubblicitari e/o promozionali.
I commenti ritenuti non conformi saranno rimossi.


Codice di sicurezza
Aggiorna

Sondaggio

Cosa vorresti vedere di più su TheTruster's Box?
 

Utenti on-line

 3 visitatori online

MasterDrive.it



Aggiungi TheTruster's Box ai preferiti!