[Parte 1Parte 2Parte 3Parte 4Parte 5]


Accesso ai dati in VB
Di:Enrico Granata



In Database esistono due metodi degni di nota: Execute ed ExecuteSQL, entrambi eseguono query SQL, ma solo query che non ritornano record, ad esempio DELETE o UPDATE

Un esempio di Excute e di ExecuteSQL è questo

MyDb.Execute "UPDATE Impiegati SET Stipendio=4000000 WHERE Anni>=20 AND Contributi>=58000000"

Dim Lines As Long

Lines=MyDb.ExecuteSQL("DELETE FROM Impiegati WHERE Anni=36")

Le due query hanno ovviamente un significato diverso, ma sono anche eseguite da metodi diversi

Iniziamo comunque a dire che la prima query assegna il valore 4.000.000 al campo Stipendio della tabella Impiegati se gli Anni sono 20 o più e i contributi sono maggiori o uguali a 58.000.000

La seconda invece elimina dalla stessa tabella tutti i record dove Anni vale 36

La cosa che però ci interessa maggiormente notare è che Execute() non ritorna nulla, mentre ExecuteSQL() ritorna un Long che indica il numero di Record influenzati dalla Query, cioè nel nostro caso il numero di record cancellati

Interessante, no?

Ma come ogni cosa ci sono i pro e i contro, perchè usare questi metodi richiede la conoscenza di SQL che è comunque trattato nella Guida in Linea di VB

A questo punto però ci possiamo chiedere come creare query che ritornino valori come SELECT?

La risposta è in un figlio di Database, RecordSet

SELECT * FROM Editori WHERE ScriveLibri='1'

Ottenere risposta da questa query è molto facile, basta usare un metodo di Database e l'oggetto Recordset

Dim MyRecordSet As RecordSet

Set MyRecordSet=MyDb.OpenRecordSet("SELECT * FROM Editori WHERE ScriveLibri=1")

Questo codice non fa altro che creare un Recordset che contiene tutti i record di Editori dove ScriveLibri è uguale ad 1

Facile, vero?

Ricordate però una cosa, questo RecordSet non è fisicamente presente nel Database, cioè una volta scritta questa linea di codice

Set MyRecordSet=Nothing

la tabella non esiste più, ma anche a questo problema c'è una soluzione, nel caso ci interessi la Tabella possiamo fare 2 cose

il metodo più ovvio è un QueryDef che si aggiorna anche nel caso la tabella Editori cambi, ma siccome in questa puntata voglio trattare i TableDef opteremo per la seconda soluzione

Iniziamo con il decidere la struttura di Editori

Nome=Text

AnnoNascita=DateTime

LibriPubblicati=Memo

FatturatoUltimoAnno=Currency

ScriveLibri=Intero

Adesso ci serve una tabella chiamati QueryEditori che creeremo con le seguenti istruzioni

Dim Table As TableDef

Set Table=MyDb.CreateTableDef("QueryEditori")

...'Codice per creare i campi

MyDb.TableDefs.Append Table

Questo codice è tutto quello che serve per creare un TableDef cioè un modello di Tabella e aggiungerlo al Database

Ma tra questo e la tabella QueryEditori finale c'è ancora molto lavoro da fare, cioè aggiungere i record

Dim MyField As Field

...'Impostazione del campo

Table.Fields.Append MyField

Come al solito il meccanismo degli insiemi ci ha ridotto di molto il lavoro, ma qualcosa da fare c'è ancora, MyField è ancora un oggetto vuoto, bisogna dargli un nome e un tipo di dati, dovete però sapere che la creazione dei record è un compito così ripetitivo e noioso che ci conviene creare una routine AggiungiCampo() che faccia il lavoro al posto nostro

Public Sub AggiungiCampo(Tabella As TableDef, Campo As Field, Nome _

As String, TipoDati As Integer)

Dim MyField As Field

'Impostazione del campo

Tabella.Fields.Append MyField

End Sub

Adesso passiamo al codice mancante, Impostazione del campo

Public Sub AggiungiCampo(Tabella As TableDef, Nome _

As String, TipoDati As Integer, Optional Dimensione)

Dim MyField As Field

If IsMissing(Dimensione) Then

Set MyField=Tabella.CreateField(Nome, TipoDati)

Else

Set MyField=Tabella.CreateField(Nome, TipoDati, Dimensione)

End If

Tabella.Fields.Append MyField

End Sub

Se il fatto che Dimensione sia Optional vi stupisce sappiate che è giusto che sia così, poichè alcuni campi ignorano l'argomento durante la creazione e pertanto inserirlo sarebbe solo uno spreco di Byte nello Stack

Adesso che abbiamo la nostra brava AggiungiCampo() possiamo anche usufruirne

AggiungiCampo(Table, "Nome", dbText)

AggiungiCampo(Table, "AnnoNascita", dbDate)

AggiungiCampo(Table, "LibriPubblicati", dbMemo)

AggiungiCampo(Table, "FatturatoUltimoAnno", dbCurrency)

AggiungiCampo(Table, "ScriveLibri", dbInteger)

MyDb.TableDefs.Append Table

Adesso posso anche dirvi che abbiamo sprecato 1 byte creando la tabella perchè l'ultimo campo poteva essere dbBoolean invece di dbInteger, c'è un modo di modificarlo, sì, ma richiede di eliminare e ricreare la tabella, pertanto ecco come eliminare la tabella

MyDb.TableDefs.Delete("QueryEditori")

il quale metodo elimina l'oggetto "QueryEditori" dell'insieme TableDefs del Database

Però questo comporta anche la creazione di una nuova "Editori" con questo campo corretto, pertanto lasciamo ScriveLibri ad Integer e da questo traiamo una regola, quando si crea un Database bisogna sedersi a tavolino e pensare alla struttura del Database ore ed ore prima di scrivere anche e solo una linea di codice

Adesso abbiamo tutte e due le tabelle e possiamo aprirle

Dim QueryEditori As RecordSet

Dim Editori As RecordSet

Set QueryEditori=MyDb.OpenRecordSet("QueryEditori")

Set Editori=MyDb.OpenRecordSet("Editori")

Da questo codice otteniamo le due tabelle aperte e pronte per le operazioni

A questo punto siamo pronti per iniziare

BeginTrans

Do Until Editori.Eof

QueryEditori.AddNew

QueryEditori("Nome")=Editori("Nome")

QueryEditori("AnnoNascita")=Editori("AnnoNascita")

QueryEditori("LibriPubblicati")=Editori("LibriPubblicati")

QueryEditori("FatturatoUltimoAnno")=Editori("FatturatoUltimoAnno")

QueryEditori("ScriveLibri")=Editori("ScriveLibri")

QueryEditori.Update

Loop

CommitTrans

Cosa significa tutto questo?

Semplice, che finchè Editori non arriva all'ultimo record ogni suo campo deve essere trasferito a QueryEditori, BeginTrans e CommitTrans indicano una transazione ed è buona norma inserirle prima di ogni modifica al DB, BeginTrans prima e CommitTrans dopo

Questo sembra proprio ciò che ci serve, ma in effetti non lo è perchè noi volevamo copiare i risultati della Query, pertanto dobbiamo cambiare il codice che apre Editori in:

Set MyRecordSet=MyDb.OpenRecordSet("SELECT * FROM Editori WHERE ScriveLibri=1")

Adesso tutto funzionerà alla perfezione tranne che ad ogni cambiamento di Editori dovremo ricordarci di eseguire questo codice, esiste poi un metodo più generico per copiare due tabelle con record uguali

BeginTrans

Do Until Editori.Eof

QueryEditori.AddNew

Dim FieldCounter As Integer

For FieldCounter=0 To Editori.Fields.Count-1

QueryEditori(FieldCounter)=Editori(FieldCounter)

QueryEditori(FieldCounter)=Editori(FieldCounter)

QueryEditori(FieldCounter)=Editori(FieldCounter)

QueryEditori(FieldCounter)=Editori(FieldCounter)

QueryEditori(FieldCounter)=Editori(FieldCounter)

QueryEditori.Update

Next FieldCounter

Loop

CommitTrans

Questo codice si basa sul meccansimo degli insiemi e degli insiemi predefinti, in quanto QueryEditori(FieldCounter) è uguale a QueryEditori.Fields(FieldsCounter) che a sua volta è uguale a QueryEditori.Fields.Item(FieldCounter) poichè ogni insieme dispone di un metodo Item che ritorna un elemento in base ad un indice, ciò per mezzo di una enumerazione, ma questo non ci riguarda direttamente, ci basti sapere che Editori.Fields.Count è conseguenza diretta dell'esistenza dell'enumerazione

Questo codice che può servire anche in lezioni successive ci conviene salvarlo in una routine di nome CopiaTabelle() così definita

Public Sub CopiaTabelle(QueryEditori As RecordSet, Editori As RecordSet)

'Codice già scritto

QueryEditori.Close

Editori.Close

End Sub

Le ultime due linee di codice aggiunte prima di End Sub chiudono la tabella QueryEditori e quella Editori, ma volendo potrebbero anche usare il metodo MoveFirst per riposizionare il Jet sul primo record

QueryEditori.MoveFirst

Editori.MoveFirst

Tra i due metodi esiste una grande differenza, cioè che il primo chiude le tabelle, il secondo permette invece di ricominciare subito a leggervi e scrivervi