Un'introduzione agli Oggetti Dati in Visual Dbase 7

Ultima modifica - 15 Marzo 1999

Ken Mayer, dBVIPS

L'obbiettivo di questo Documento

Questo documento e' stato creato per aiutare un programmatore nuovo all'ambiente Visual Dbase 7 a capire gli oggetti Dati. Questi oggetti sono necessari per aiutare uno sviluppatore ad usare Visual Dbase 7 al massimo delle sue potenzialita'.A tal fine questo sara' probabilmente un documento abbastanza lungo, cosi' come coprira' il lato "pratico" di lavorare con questi oggetti, discutendo le proprieta', eventi e metodi di ciascuno di essi, discutendo le relazioni di ciascuno oggetto con gli altri e cosi' via.

Uno sviluppatore nuovo a questo ambiente puo' anche voler esaminare alcuni degli altri documenti HOW TO al sito web dell'autore (indicato nel sommario di questo documento), includendo (ma non limitandosi ad essi) X2OODML.ZIP e MISCCODE.ZIP. Si dovrebbe anche visitare il sito web di Alan Katz e scaricare il suo documento OODML.HOW, che discute i concetti e la teoria dell' Object Oriented Database Manipulation Language.Il sito di Alan e'

http://www.ksoftinc.com/vdb

__________________________________________________________________________________

AVVISO:Questo documento ha lo scopo di aiutarti ad iniziare e non puo' coprire ogni diversa cosa che tu programmatore, puoi desiderare o hai bisogno di effettuare. Uno dei punti di forza ed anche uno dei fattori che confondono del Dbase e' che e' flessibile. A causa della sua flessibilita', un programmatore puo' confondersi cercando di trovare la giusta via per fare qualcosa per le proprie ( o piu' importante dei propri clienti) necessita'.

La cosa migliore da fare e' di usare questo documento, gli altri documenti menzionati, e la migliore risorsa disponibile, i Newsgroup del Visual Dbase messi a disposizione da Dbase Inc. Se non si riesce a fare qualcosa, visita i newsgroup e poni una domanda. Alla maggior parte delle domande viene data una risposta entro poche ore. ________________________________________________________________________________

Menu

Uno sguardo d'insieme

Oggetti Dati ? Che cosa sono mai gli oggetti dati ?

dBASE, Inc. ha preso il modello ad oggetti di prim'ordine che era stato creato per il Visual dBASE 5.x, e lo ha incluso nelle tabelle e nei database. Questo significa che si possono ora usare tabelle, records, e campi come oggetti, ognuno di essi con il proprio set di proprieta', eventi e metodi. Questo da' al programmatore molto controllo sul codice, e gli da' anche molta della potenza e riusabilita' del linguaggio orientato agli oggetti che si puo' ottenere dagli altri oggetti in dBase. E cosi',quali sono questi oggetti e come essi sono collegati fra loro? Prima che si vada in profondita' nella discussione facciamo un passo indietro e diamo uno sguardo agli oggetti Dati in Visual dBASE.

La maggior parte di questi oggetti sono contenitori. Cio' significa che essi possono avere all'interno altri oggetti. Un esempio di oggetto di questo tipo che sara' utilizzato spesso e' l'oggetto Query. Questo oggetto ha all'interno un oggetto rowset cosicche' esso e' un contenitore per l'oggetto rowset. Diversamente da altri contenitori vi puo' essere solo un oggetto rowset per ciascun oggetto query. L'oggetto rowset e' un contenitore di un array di campi. L'array di campi contiene i puntatori a ciascun oggetto campo che e' contenuto nel rowset. Quindi si puo' disegnare un diagramma come il seguente:

(Graphic courtesy of Gary White)

L'oggetto rowset ha un genitore, che e' la query, gli array di campi hanno un genitore che e' l'oggetto rowset, gli oggetto campo hanno un genitore che e' l'array di campi.

Da notare che non si puo' definire un oggetto rowset indipendentemente dall'oggetto query, ma puoi definire un oggetto campo indipendente da un array di campi o da un rowset (ma il suo uso all'esterno del rowset e' abbastanza difficoltoso, a meno che non lo si aggiunga all'array di campi di un rowset -- Gary White sta considerando una maniera di creare eventi usando l'oggetto campo ...).

Ora, per rendere le cose piu' interessanti, un oggetto database si riferisce ad un alias BDE. Un database, per sua vera natura, contiene tabelle. In tal modo l'oggetto database e' un riferimento ad un oggetto -- il database stesso. Tuttavia cosi' si semplifica troppo l'argomento. Si dovrebbe considerare l'uso di un BDE alias per le ragioni che saranno discusse quando si trattera' dell'oggetto database.

Un oggetto sessione e' usato per trattare accessi simultanei al database. (Lo scenario piu' probabile potrebbe essere una applicazione MDI dove possono essere aperte diverse mappe che accedono alle stesse tabelle.

Stored Procedures possono essere usate solo con tabelle SQL Server, e sono usate per accedere a procedure conservate sul database del server.

Le tabelle Standard locali non riconoscono le Stored Procedures e tentare di usarle su tabelle locali puo' causare problemi.

Un datamodule puo' essere usato per contenere: oggetti database, oggetti stored procedure, oggetti sessione ed oggetti query. I rowset sono, come notato in precedenza, contenuti automaticamente dalle query, cosi' mentre un datamodule contiene la query, esso non contiene direttamente il rowset.

Quanto sei confuso in questo momento? Spero non troppo.... Tutto questo conduce a qualcosa...vediamolo.

NOTA: Un aspetto che confonde un po' quando si lavora con gli oggetti dati in Visual Dbase e' che gli oggetti dati non hanno un riferimento alla form (o al report). Cio' significa che quando si progetta del codice contenente eventi e metodi degli oggetti dati, non ci si puo' riferire direttamente ad oggetti su una form o su un report. Vi sono delle maniere per aggirare questo problema, ma non si discutera' di esse qui, poiche' non si vuole confondere oltre quanto lo si possa gia' essere.

Una dettagliata Analisi di ciascun oggetto Dati.

Ciascuno di questi oggetti dati, come gia' notato in questo documento, ha proprieta', eventi e metodi.

Proprieta'
Le proprieta' sono gli attributi dei controlli. L'impostazione di una proprieta' puo' essere effettuata a programma cosi' come negli ambienti di progettazione (form, report, datamodule).L'impostazione e' normalmente costituita da un singolo valore, per esempio, una stringa di caratteri, un numero o un riferimento ad un altro oggetto.

Eventi

Gli eventi sono qualcosa a cui i controlli possono rispondere, un click del mouse, un controllo che ottiene il fuoco, una variazione del valore di un controllo. Tuttavia, al verificarsi dell'evento, perche' effettivamente avvenga qualcosa, si deve agganciare a tale evento del codice.

Eventi il cui nome inizia con ON, come onOpen, avvengono dopo l'azione alla quale essi si riferiscono. Cosi' l'evento onOpen avviene dopo che la query e' aperta. La seconda cosa e' che gli eventi che iniziano con CAN, come canClose, devono restituire un valore logico che determinera' se l'azione indicata puo'continuare. Cosi' l'evento canClose di una query deve ritornare true prima di poter chiudere la query. La restituzione di un valore false non permettera' la chiusura della query. La mancata restituzione di un valore Booleano puo' dare risultati imprevedibili.

Metodi

I metodi sono codice che effettua un'azione. Gli oggetti hanno un certo numero di metodi predefiniti che sono chiamati attraverso il controllo, p.es. form.rowset.next()

Una cosa che va tenuta presente e' che, se si usano i metodi predefiniti per inserire il proprio codice (over-riding del metodo), si dovra' quasi sempre chiamare il metodo predefinito, prima, dentro o dopo il proprio codice (Cio' puo' essere ottenuto inserendo SUPER::methodname() nel codice...).

SESSION
Un oggetto session e' come un contenitore. Esso puo' essere usato sia con un oggetto database sia direttamente con un oggetto query (tuttavia, se si sta usando un oggetto database, si dovrebbe usare la sessione con il database, non la query...).

Nelle precedenti versioni di Dbase, le sessioni erano necessarie quando una applicazione permetteva un accesso multiplo alle stesse tabelle dentro una "sessione" dell'applicazione. Se le tabelle vengono aperte ognuna nella propria sessione, si evitano alcuni tipi di conflitto (non tutti).

In Visual dBASE 7, il solo, reale, obbiettivo di usare un oggetto sessione e' raggiunto quando si desidera usare l'evento onProgress (per agganciarsi ad una bar progress) o se si stanno usando tabelle criptate (si puo' effettuare l'"auto login"). Oltre a questi casi , l'uso delle sessioni confonde ed aggiunge un livello di difficolta' in piu' a quello che lo sviluppatore sta facendo.

Le Sessioni hanno le seguenti proprieta', eventi e metodi:

Per creare una nuova sessione tutto quello che si deve fare e':

sMySession = new Session()

Per usare una sessione si deve assegnare una proprieta' sessione a quegli oggetti ( database e query) che sono influenzati da quella specifica sessione.

Per esempio:

sMiaSession = new Session()

dMioDatabase = new Database()

dMioDatabase.databaseName := "MioAlias"

dMioDatabase.session := sMiaSession

dMioDatabase.active := true

qMiaQuery = new Query()

qMiaQuery.database := dMioDatabase

qMiaQuery.session := sMiaSession

qMiaQuery.sql := "select * from MiaTabella"

qMiaQuery.active := true

qMiaQuery2 = new Query()

qMiaQuery2.database := dMioDatabase

qMiaQuery2.session := sMiaSession

qMiaQuery2.sql := "select * from MiaTabella2"

qMiaQuery2.active := true

Default Session

Si noti che c'e' sempre una sessione di default, che e' accessibile attraverso l'oggetto database di default dell'oggetto applicazione:

?_app.databases[1].session.access()

Se si desiderano usare sessioni nelle proprie applicazioni si dovrebbe valutare la possibilita' di impostarle nei propri datamodules, forms o report (secondo il progetto dell'applicazione). Si consulti l'aiuto in linea per maggiori dettagli sull'uso delle sessioni.

DATABASE

L'oggetto database e' usato quando si usano gli Alias BDE per gestire i propri archivi di dati. Per maggiori dettagli sugli Alias BDE si dovrebbero leggere MISCCODE.ZIP, nel sito web dell'autore, cosi' come la Guida al Programmatore che arriva con il dBASE e l'aiuto del BDE....

Un alias e' assolutamente richiesto quando si lavora con le tabelle SQL Server (come Interbase, Oracle, ecc.) ed e' opzionale ma utile quando si usano tabelle locali.

Se si decide di usare un alias, si dovrebbe usare un oggetto database nel proprio codice e nelle proprie forms, reports, datamodules ecc.

Se si sta lavorando solo con tabelle locali, perche' si dovrebbe usare un Alias BDE e quindi un oggetto database?

Qui ci sono le proprieta' e metodi (non ci sono eventi) dell'oggetto database (alcuni di questi non sono coperti in gran dettaglio qui, poiche' l'autore non usa tabelle SQL Server... Vedi l'aiuto in linea per maggiori dettagli). E' importante notare che dBase ha un database di default, che punta alla "directory corrente". A questo si puo' sempre accedere attraverso l'oggetto applicazione:

_app.databases[1]

E qualsiasi metodo dell'oggetto database puo' essere eseguito:

_app.databases[1].packTable( "MyTable" )

La proprieta' active del database di default non puo' essere modificata -- si puo' tentare di impostarla a false, ma non avverra' nulla. Il database di default ha anche una sessione di default (si veda sotto).

Creazione di un riferimento ad un oggetto Database

Si puo' creare un riferimento ad un oggetto database in maniera abbastanza semplice. Ci sono solo alcune cose che si devono impostare:

d.databaseName := "MyAlias"

d.active := true

// for a SQL Server database

d = new Database()

d.databaseName := "MyAlias"

d.loginString := "username/password"

d.active := true

// Assign a new session:

s = new Session()

d.databaseName := "MyAlias"

d.session := s

d.loginString := "username/password"

d.active := true

Transaction Processing

Uno delle cose per cui si puo' desiderare usare l'oggetto database e' per la gestione delle transazioni. Molte applicazioni di questi giorni non usano piu' le transazioni, ma e' ancora qualcosa di cui si puo' avere necessita' per le proprie applicazioni o che gli utenti possono preferire.

Una transazione e' un procedimento grazie al quale si svolgono in successione una serie di operazioni senza che l'utente intervenga. Questo procedimento e' qualche volta chiamato "batch".

Quando si attiva un database, si puo' iniziare una transazione, con il metodo del database beginTrans():

// per tabelle locali

d = new Database()

d.databaseName := "MyAlias"

d.active := true

d.beginTrans()

// fa qualcosa -- inizia l'applicazione

// o carica la form e permette all'utente

// di fare il proprio lavoro ... etc.

d.commit() // salvera' le transazioni, ed aggiornera'

// le tabelle in maniera appropriata

// Oppure

d.rollback() // cancellera' tutte le transazioni iniziando

// da quando il metodo beginTrans() e' stato chiamato.

Metodi di Manutenzione delle Tabelle

Ci sono diversi metodi che sono collegati all'oggetto database che replicano alcuni dei comandi Xbase DML. Brevemente essi sono:

Se si sta lavorando solo con tabelle locali allora l'oggetto STOREDPROC risulta privo di utilita'. Tuttavia se si lavora con database SQL Server (o "backend server") allora questo oggetto puo' essere molto utile.

Non ho diretta esperienza con tale oggetto cosi' dovrete avere pazienza. Dopo avere descritto le proprieta' non ho molto altro da dire....

"Un oggetto StoredProc serve per chiamare una procedura memorizzata in un database. La maggior parte delle procedure memorizzate richiede uno o più parametri di input e può restituire uno o più valori di output. I parametri vengono passati e ricevuti dalla procedura memorizzata tramite la proprietà params dell'oggetto StoredProc, la quale punta ad un array associativo di oggetti Parameter.

Alcune procedure memorizzate restituiscono un rowset. In tal caso, l'oggetto StoredProc è simile ad un oggetto Query, con la differenza che, anziché eseguire un'istruzione SQL che descrive i dati da recuperare, si definisce il nome di una procedura memorizzata, le si passano i parametri e la si esegue. Al rowset risultante si accede tramite la proprietà rowset dell'oggetto StoredProc, proprio come avviene in un oggetto Query.

Poiché le procedure memorizzate sono basate su server SQL, occorre creare ed attivare un oggetto Database, da assegnare poi alla proprietà database dell'oggetto StoredProc. Le tabelle standard non sopportano le procedure memorizzate.

Quindi, bisogna impostare la proprietà procedureName al nome della procedura memorizzata. Per la maggior parte dei server SQL, BDE può acquisire i nomi e i tipi dei parametri per la procedura memorizzata. Su alcuni server non è disponibile alcuna informazione; in questo caso, nella proprietà procedureName occorre includere anche i nomi dei parametri".

Vi sono delle altre informazioni nell'aiuto in linea se si necessita di maggiori spiegazioni.

QUERY

L'oggetto Query e'l'oggetto dati piu'spesso incontrato. L'oggetto query e' usato per creare un riferimento alle singole tabelle del proprio database, ed e' obbligatorio quando si lavora con tabelle che usano l'OODML.

E' quindi davvero importante che lo si comprenda bene. Esso e' il contenitore del rowset, che e' dove si trovano la maggior parte dei metodi e degli eventi che gestiscono i dati, cosi' come il rowset e' un contenitore per i campi... Prima che si parli del suo uso, diamo un'occhiata alle proprieta', agli eventi ed ai metodi della query.

Come usare una query?

Si ritornera' su questo argomento, ma per iniziare, ed assumendo che si sta lavorando con tabelle locali, sara' necessario creare una instanza (copia) della query, assegnare la proprieta' SQL, e quindi porre la sua proprieta' active a true.

q = new query()

q.sql = "SELECT * FROM mytable"

q.active = true

Una cosa che qualche volta preoccupa i nuovi utilizzatori del Visual Dbase e' che essi "devono conoscere l'SQL". No, non e' necessario. Il comando sopra citato e' la maggior parte dell'SQL che si deve assolutamente conoscere per costruire delle applicazioni Visual dBase molto dettagliate. La maggior parte di quello che si puo' desiderare di fare e' incluso nelle proprieta', negli eventi e nei metodi dell'oggetto rowset che si trattera' tra poco.

L' "*" nell'istruzione SELECT e' una wildcard, come in DOS -- essa significa quando e' usata nella SELECT, "tutti i campi".

Le tre istruzioni di sopra sono le sole necessarie se si sta creando un programma che manipola dati, ma cosa bisogna fare se si desidera usare una form o un report ?

Non potrebbe essere piu' semplice. Si apra una form nell'editor di form, si clicchi su "Tabelle" nel centro di controllo e si trascini la tabella che si desidera usare sulla superficie della form (o del report). Si vedra' un'icona che rappresenta l'oggetto query. Questa ha le lettere SQL su di essa. L'editor di form automaticamente crea il codice SQL necessario, sebbene tale codice si presenta in maniera diversa se si esamina il sorgente:

this.CUSTOMER1 = new QUERY()

this.CUSTOMER1.parent = this

with (this.CUSTOMER1)

left = 52.5714

top = 2.5

sql = "select * from customer"

active = true

Endwith

Gli editor impostano automaticamente le proprieta' left e top cosi' che ogni volta che si apre la form l'icona della query si trova nello stesso posto. Quando si esegue la form, l'icona della query non comparira' nella form, essa si vedra' solo in fase di progettazione.

La prima istruzione crea una instanza dell'oggetto query, ma si noti che piuttosto che "CUSTOMER1" si vede "this.CUSTOMER1" -- "this" si riferisce alla form. Si noti anche che la proprieta' parent viene automaticamente assegnata ed ancora "this" si riferisce alla form.

Si potrebbe scrivere lo stesso codice mostrato all'inizio in un modo simile nel proprio programma:

q = new Query()

with( q )

sql = "select * from mytable"

active = true

endwith

Questa scrittura e' valida come la precedente.

Istruzioni SQL SELECT

Se si esamina qualsiasi libro sull' SQL, si trovera' che ci sono molte opzioni che si possono usare con l'istruzione SQL Select.

Come notato sopra, non si deve realmente sapere molto sulle istruzioni SQL Select per usare questi oggetti Dati. Tuttavia, si dovrebbero conoscere un po' di cose, particolarmente se si e' familiari con l'SQL.

La clausola WHERE lavora bene, ma ci sono alcuni avvertimenti.

// or Query a sola lettura

Local SQL (istruzioni SQL usate su tabelle locali ) spesso genereranno queries a sola lettura. Le istruzioni seguenti genereranno queries a sola lettura:

ROWSET
L'oggetto rowset e' il vero cavallo di battaglia degli oggetti Dati in Visual dBASE. La maggior parte delle funzionalita' presenti nei comandi e nelle funzioni DML del vecchio Xbase si trovano ora nelle proprieta', negli eventi e nei metodi dell'oggetto rowset (vedi X2OODML.ZIP).
Wow! C'e' molta carne al fuoco! Il problema e' che si e' dato appena un rapido sguardo e ci si puo' chiedere come si usi tutto cio'. Non si disperi, si copriranno alcuni aspetti in maggior dettaglio e vi sono altri esempi sia nei documenti HOW TO nel sito dell'autore che nell'aiuto in linea...Perora si stanno soltanto guardando le varie componenti, piu' tardi si cerchera' di metterle assieme. Per definire un indice .DBF e quindi crearlo, si deve operare nella maniera seguente:

i = new DBFIndex()

i.indexName := "MioIndice"

i.expression := "field1 + upper(field2)"

// un'altra caratteristica non documentata:

_app.databases[1].createIndex( "NomeTabella", i )

Questo e' realmente tutto cio' che e' richiesto. Se si vuol fare qualcosa di piu' si deve impostare il tipo a 1 per .NDX (da notare, tuttavia, che l'OODML non sa come gestire un file .NDX ), si puo' impostare la proprieta' unique a true, la proprieta' descending a true e cosi' via. Si ricorda che l'espressione per l'indice deve essere corretta.

Qualcosa in piu' sulle espressioni

Per il momento si assume che si sta lavorando con .DBF, poiche' tale tipo di files e' quello nativo per il Dbase. Si discuteranno brevemente un po' di cose.

Indici numerici

Definire indici numerici non e' generalmente una buona idea. Nella maggior parte dei casi si dovrebbe indicizzare su stringhe di caratteri. "La maggior parte dei campi chiave sono essenzialmente caratteri, anche se essi contengono dei numeri. Per esempio, numeri di telefono, CAP , partite IVA non hanno niente di numerico. Una buona maniera di procedere e' che se non si devono effettuare calcoli aritmetici con essi, tali campi dovrebbero essere caratteri." -- Gary Thoenen [dBVIPS]

Date
La gestione delle date puo' essere interessante. Se si stanno usando date nel formato Americano MM/DD/YYYY, e si imposta un indice sulla data "cosi' come e' " , cosa capitera' se si hanno date che coprono diversi anni ? L' ordinamento sara' effettuato per mese, piuttosto che per anno e per mese.

Posiamo allora impostare il formato della data a YY/MM/DD, che e' piu' logico (Anno, Mese, Giorno).Cosa capitera' allora quando arrivera' l'anno 2000 ? Tutte le date relative all'anno 2000 appariranno nell'indice prima dell'anno 1999. Questo non e' probabilmente una cosa desiderabile. La maniera migliore di procedere per indicizzare le date e' di usare la funzione DTOS. DTOS() ritorna date come una stringa di caratteri nel formato YYYYMMDD (senza barre).

La cosa interessante e' che questo stratagemma funziona con tutti i formati internazionali di data.

Lunghezza delle espressioni

La lunghezza massima di una espressione puo' essere di 100 caratteri, ma questa e' realmente una espressione troppo lunga. Se si sta lavorando con campi multipli e si combinano in una espressione che e' piu' lunga di 100 caratteri, Dbase non la considerera'. Come aggirare il problema ? Si usi la funzione left() per estrarre da ciascun campo una parte tale da ottenere valori unici di chiave e tutto lavorera' perfettamente. Se per esempio si sta lavorando con una collezione di CD, molti titoli di album sono piuttosto lunghi (uno che mi passa per la mente e "I Miti e le Leggende di Re Artu' e dei Cavalieri della Tavola Rotonda" di Rick Wakeman..). Si puo' desiderare di avere un indice sul nome dell'artista e quindi sul titolo dell'album. Ma se il campo artista e' diciamo, 40 caratteri, ed il campo titolo e' 100, si possono avere dei problemi. Per creare una espressione relativa a questo indice, si puo' probabilmente prendere l'intero nome dell'artista e quindi solo i primi 40 caratteri (o meno) del titolo:

i.expression := artista+left( titolo, 40 )

Dipendenza dal Maiuscolo/Minuscolo

Le espressioni di indice DBF sono sempre stati sensibili al Maiuscolo/Minuscolo. Non si sa mai quello che un utente fara' con tuo programma. La maniera' piu' sicura di costruire con una espressione e di crearla non dipendente dal Maiuscolo/Minuscolo. Come ottenere cio'? Si indicizzi su una stringa di caratteri MAIUSCOLI e si abbia la certezza che le procedure di ricerca convertino in maiuscolo i valori inseriti dall'utente. Per creare un'espressione , si deve usare:

i.expression := upper( artista+left( titolo, 40 ) )

Come ottenere informazioni sulle etichette degli indici.

Non e' facile ottenere informazioni attorno ai propri indici, a meno che non si usi il non documentato oggetto TableDef.

Questo argomento e' coperto in dettaglio nel documento dell'autore presentato a Icon98 sulle Undocumented Features al suo sito web.

Miscellanea

Si tenga presente che piu' etichette di indici si hanno in una tabella, piu' tempo e' necessario per aggiornare una tabella, includendo l'aggiunta di nuove righe, la modifica di righe (specialmente se all'utente e' permesso di modificare campi usati nelle espressioni delle proprie etichette di indici) e cosi' via. Se si effettuano variazioni a programma alle proprie tabelle, la situazione puo' peggiorare. Ci sono delle maniere per aggirare questi problemi, ma non verranno per il momento prese in considerazione.

Vi sono maggiori informazioni sugli indici nel documento presentato dall'autore a Icon98 su Undocumented Features e disponibile nel suo sito web...

ARRAY DI CAMPI

Questo e' un argomento davvero semplice. L'array di campi e' un array che e' contenuto dal rowset e contiene i puntatori agli oggetti campo per il rowset. Che cosa si puo' fare con un array di campi? Ebbene, l'array di campi permette di individuare i campi. Si possono aggiungere o cancellare campi nell'array di campi (utile per campi calcolati, un argomento che si trattera' successivamente). Si puo' anche sapere quanti campi vi sono nell'array di campi. Non c'e' molto altro. Ecco una lista delle proprieta' e dei metodi.

? form.rowset.fields[ 1 ].value

// or

? form.rowset.fields[ "fieldName" ].value

Piuttosto che spendere molto tempo su quest'argomento, diamo un'occhiata all'oggetto campo.C'e' molto da vedere li'...

FIELD
L'oggetto FIELD e' usato per consentire l'accesso a campi individuali in una tabella e lavorare con proprieta', eventi e metodi per modificare il comportamento ed il valore del campo. Ci sono in realta' differenti tipi di oggetti FIELD. I primi due tipi sono sottoclassi dell'oggetto FIELD principale. Se si sta lavorando con un .DBF, allora automaticamente si sta usando un DBFFIELD, o, nel caso di una tabella che e' stata convertita (usando il comando Xbase CONVERT per aggiungere il campo _DBASELOCK) si avra' un LOCKFIELD. Si possono incontrare anche i tipi di campo PDXFIELD e/o SQLFIELD, ciascuno dei quali ha proprieta' specifiche per quel tipo di campo.

Di seguito sono enumerate tutte le proprieta' dei campi, e se non sono comuni alla classe FIELD, viene data una nota per quel tipo di campo.

Si ha fiducia a questo punto nel fatto che le varie parti si stanno riunendo. O avviene questo o i propri occhi si stanno trasformando in gelatina. Se quest'ultimo e' il caso ci si allontani dal computer per un po',quest'ultimo tanto rimarra' dov'e'.

Ora che abbiamo esaminato gli oggetti Dati piu' importanti in Visual Dbase 7 cerchiamo di usarli un po'. Questo documento non puo' probabilmente coprire ogni singola caso nel quale lo sviluppatore puo' imbattersi quando usa una specifica funzionalita'. Tuttavia con un po' di fortuna posso ottenere almeno il risultato che egli ci rifletta su....

La maggior parte di quanto segue assume che si stanno usando forms (e/o reports, le idee sono per buona parte uguali) e cosi' la sintassi per i comandi indicati presupporra' forms, o in molti casi l'evento onClick dei controlli pushbutton su forms. Si tenga presente che lo stesso tipo di cose puo' essere effettuato tramite programma.

Come usare una Tabella in una form

Dopo tutta questa babele di informazioni, sicuramente si ha l'impressione che cio' che si sta andando a fare sia complicato, non e' cosi'?

Cio' che segue e' valido per i reports e le etichette cosi' come per le forms.

In realta' non potrebbe essere piu' semplice. Per usare una tabella su una form, il metodo piu' semplice e' di aprire una nuova form nell'editor di form, cliccare sul Centro di Controllo in Visual dBase 7, cliccare su "Tabelle", e trascinare la propria tabella sulla superficie dell'editor di form.

Avverra' che dBase porra' un'icona sulla superficie della form, che e' usata per rappresentare un oggetto non-visuale (quando la form viene eseguita, l'utente non vedra' quest'oggetto). L'icona avra' le lettere "SQL" su di essa --- questo e' un oggetto query. In piu' posizionando l'icona sulla superficie dell'editor dBase impostera' la proprieta' SQL, e la proprieta' active verra' posta per default a "true".

Se si sta usando un Alias BDE, si avra', oltre all'oggetto query, anche un oggetto database.

L'editor di form automaticamente effettuera' le corrette connessioni fra l'oggetto database e l'oggetto query.

Se si ha bisogno di qualcosa di piu', come impostare un'espressione di indice affinche' sia l'indice principale, e' necessario effettuare un "drill down" nell'Ispezione. Si clicchi sull'icona SQL della tabella ed in Ispezione, si clicchi sulla parola "rowset". Si vedra' "Oggetto" nella seconda colonna ed avra' un pulsante con la lettera "I" ("Inspect") su di esso. Si clicchi sulla I. Ora si vedra' l'oggetto rowset associato con la query. Si clicchi sulla proprieta' "indexName" e si selezioni l'etichetta dell'indice che si desidera usare. Tutto cio' e' abbastanza facile.

Cliccando sulla "I" di fields si vedra' normalmente una tavolozza di "campi". Se non e' cosi' si clicchi col pulsante destro sulla superficie di progettazione della form e si selezioni "Tavolozza di Campi". Cosi' si visualizzeranno i campi della propria tabella. Essi possono essere trascinati, se si vuole, direttamente sulla superficie di progettazione....

L'inizio e' abbastanza facile, eh? C'e' molto di piu', ma qui non c'e' molto spazio per andare in dettaglio. L'autore tentera' di creare un tutorial, in un prossimo futuro, su come creare un'applicazione e una buona parte di esso sara' speso nella creazione delle forms... Tuttavia, nel frattempo, si possono consultare "CONTROLS.ZIP", "CUSTCTRL.ZIP", "GRID.ZIP", ed altri HOW TO a loro collegati nel sito web dell'autore.

Una cosa che e' importante notare e' che la form stessa ha una proprieta' chiamata "rowset". dBASE automaticamente inserisce un riferimento alla prima query posta sulla form in questa proprieta' della form.

Navigando attraverso le Tabelle

Una volta che si ha una tabella su una form, e presumibilmente alcuni controlli per i campi, si dovra', perlomeno, permettere all'utente di navigare attraverso la tabella.

Se si e' posti la proprieta' indexName dell'oggetto rowset, la tabella sara' percorsa sulla base della sequenza prevista dall'espressione dell'indice.

La navigazione e' effettuata attraverso i metodi del rowset che sono stati gia' discussi nella sezione relativa al rowset di questo documento. Vi sono alcune cose che si dovrebbero osservare:

Se si decide di scrivere da se' il codice per la navigazione nella tabella, vi sono alcune cose da considerare: Si puo' impostare un rowset affinche' non sia modificabile fino a quando l'utente non decida esplicitamente di voler effettuare una modifica (Io trovo che questa sia una buona idea -- e' davvero facile variare accidentalmente qualcosa...) Cambiando la proprieta' del rowset autoEdit a false (per default e' true). Questo ha l'effetto di disabilitare tutti i controlli che sono dataLinkati ai campi del rowset.

Se si decide di usare la proprieta' autoEdit a false, allora si dovra' fornire una maniera all'utente di modificare la riga corrente. Questo puo' essere fatto con:

form.rowset.beginEdit()

e tale codice puo' essere posto nell'evento onClick di un pulsante.

Si dovrebbe anche fornire una opzione "save" e una "cancel" per chiamare i metodi save() ed abandon() del rowset.

Un problema che arriva con i Comboboxes ...
Se si usa questo metodo per disabilitare i controlli, il combobox sembra attivo anche quando non lo e'. L'utente puo' selezionare un nuovo valore, e sembra che questo valore modifichi la riga, fino a quando l'utente non passi ad un'altra riga o non vada in modalita' edit (od effettui qualsiasi altra azione che aggiorni i controlli datalinkati dei valori nei campi).

Cio' puo' essere sconcertante. Tuttavia Gary White ha fornito la seguente soluzione per questo problema. Bisogna inserire il seguente codice negli eventi onGotFocus e onChange per il combobox:

function combobox1_onGotFocus

this.savedValue = this.value

return

E nell'evento onChange:

function combobox1_onChange

// this = combobox

// datalink = field

// parent = field array

// parent = rowset

if this.datalink.parent.parent.state == 1

this.value = this.savedValue

endif

return

Si noti che affinche' il tutto funzioni si devono usare entrambi questi eventi. (Si puo' anche aggiungere dell'altro codice nell'evento onChange, si deve soltanto mantenere il codice sopra riportato... magari aggiungendo un 'return' prima dell'istruzione endif).

Un problema simile che arriva con gli Editors....

Il controllo editor e' anche peggiore sotto quest'aspetto, poiche' esso ignorera' lo stato del rowset.

Tuttavia Gary White ci fornisce, anche in questo caso, il seguente fix...

function key

/*

Questo codice di Gary White e' finalizzato all'aggiramento

di un problema con i rowset che hanno la proprieta'

autoEdit posta a false, e gli editors. L'editor sembra immune

a questa proprieta' del rowset ed i suoi contenuti possono

essere modificati qualunque sia lo stato del rowset...

*/

// this = editor

// dataLink = field

// parent = fieldArray

// parent = rowset

if type( "this.datalink.parent.parent" ) # "U"

r = this.datalink.parent.parent

if r.autoEdit == false and ;

( r.state # 2 and r.state # 3 )

return 0

endif

endif

Cancellazione di righe

L'OODML non supporta il "soft delete" Xbase (fondamentelmente questa e' la capacita' di continuare a mostrare una riga cancellata sulla form) direttamente. E' possibile fare cio' attraverso le API del BDE e c'e' un esempio di questo in "X2OODML.ZIP" nel sito web dell'autore (e nella libreria dUFLP nello stesso sito).

La ragione di cio' sta nel fatto che .DBF e' la sola tabella che permette questa funzionalita' -- tutte le altre assumono che una riga cancellata non sia piu' presente. Niente paura, tuttavia: se l'utente decide di cancellare una riga essa e' ancora nella tabella, ma non la si puo' mostrare all'utente, e non si puo' (usando l'OODML) permettere all'utente di richiamare (undelete) quella riga.

Come trovare delle righe in una Tabella

Vi sono diverse maniere di "trovare" righe in una tabella. Si puo'usare "findkey" e/o findKeyNearest()", si puo' usare "beginLocate()" e "applyLocate()", e molto di piu'. Tutto cio' e' discusso in "MISCCODE.ZIP" nel sito web dell'autore in maggiore dettaglio.

Come filtrare delle righe in una Tabella

Cosi' come "trovare" delle righe, vi sono diverse maniere di filtrare delle righe in una tabella, includendo la proprieta' "filter" del rowset, i metodi "beginFilter()" e "applyFilter()", il metodo "setRange()" e l'evento "canGetRow" del rowset. Tutto cio' e' discusso in "MISCCODE.ZIP" nel sito web dell'autore in maggiore dettaglio.

Tabelle collegate

Nelle precedenti versioni di dBase si sono usati diversi comandi per impostare relazioni
(SET RELATION, SET SKIP ...). Nell'OODML di Visual dBASE 7's OODML questo e' stato reso piu' semplice. Vi e' una discussione abbastanza estesa di cio' nel documento "MISCCODE.ZIP" HOW TO nel sito web dell'autore.

Campi calcolati

I campi calcolati sono piuttosto importanti in un gran numero di applicazioni.. Essi sono semplici campi che visualizzano un calcolo o un valore non presente nella tabella per l'utente (qualcuno pensa che un campo calcolato sia specificatamente finalizzato ai calcoli matematici, invece la combinazione di due campi in uno e' considerato un campo calcolato ed ottenere un valore da un lookupRowset e' un campo calcolato). L'utente non puo' direttamente agire con loro, poiche' essi sono, per loro natura, campi a sola lettura- essi non sono direttamente collegati ad una tabella. (L'utente puo' in realta' modificare tali campi a meno che non imposti la proprieta' ReadOnly sul campo, ma tale modica non si riflettera' sulla tabella stessa...)

Per creare un campo calcolato si deve creare un'istanza di un campo oggetto, impostare alcune proprieta' (come discusso sotto), e quindi aggiungere il campo all'array di campi per il rowset. Se impostato nella maniera opportuna, poiche' l'utente naviga attraverso la tabella, questo campo sara' calcolato (usando l'evento beforeGetValue) e i risultati si visualizzeranno sulla form o sul report di stampa.

Il seguente e' un semplice esempio di come si crea un campo calcolato per visualizzare il " nome completo" partendo dai campi nome e cognome nella tabella. Si tenga a mente che qualsiasi espressione valida per il Visual dBase funzionera'. Questo esempio assume che il campo oggetto venga aggiunto in un evento canOpen o onOpen della query.

// istanziazione dell'oggetto campo

f = new Field()

f.fieldName := "Full Name"

f.readOnly := true

// "this" nella seguente istruzione si riferisce

// all'oggetto campo (importante informazione)

f.beforeGetValue := {|| trim( this.parent["first name"].value ) + " " +this.parent["last name"].value }

// "this" nella seguente istruzione si riferisce alla query:

this.rowset.fields.add( f )

E' davvero importante che si usi l'evento beforeGetValue per eseguire realmente il calcolo, o il valore non si aggiornera' quando si naviga attraverso la tabella. Se si assegna invece la proprieta' "value", tale valore verra' visualizzato solo per la prima riga visualizzata e non si aggiornera' quando si naviga fra i records.

Si possono avere vari campi calcolati per un rowset e si deve solo cercare di essere sicuri che ciascuno abbia una proprieta' fieldName unica.

TableDef

L'oggetto tableDef e' una risorsa non documentata del Visual Dbase 7. Esso e' estremamente utile, in quanto puo' visualizzare informazioni su una tabella, sugli indici di una tabella, sui campi di una tabella e su qualsiasi vincolo definito nella tabella.(Tuttavia, non si puo' scrivere nessuna di queste informazioni usando tableDef).

Piuttosto che duplicare informazioni gia' scritte, si dovrebbe esaminare il documento di Icon98 su Undocumented Features nel sito web dell'autore. Questo particolare oggetto e' descritto in maniera estesa, con esempi di codice e piu' in quel documento.

UpdateSet

L'oggetto UpdateSet in Visual dBASE e' utile per effettuare aggiornamenti di gruppo (batch) alle tabelle e/o copiare tabelle da un formato ad un altro. Per maggiori dettagli sull'oggetto UpdateSet, si veda "MISCCODE.ZIP" nel sito web dell'autore. In tale documento l' argomento e' coperto in dettaglio ed e' piu' facile effettuare dei riferimenti a quel documento che cercare di mantenere informazioni duplicate in diversi posti.

DataModules

Un DataModule e' un oggetto speciale in Visual Dbase. Esso e' un contenitore per oggetti Dati. Il suo scopo principale e' di migliorare il modello ad oggetti e le possibilita' di "riusabilita' del codice" per una migliore programmazione orientata agli oggetti.

L'importanza di un datamodule sta nel fatto che si possono impostare le proprie tabelle e qualsiasi codice si desidera impostare per quelle tabelle in un datamodule, e usare tutto quel codice senza dover ricrearlo per ciascuna form o report.

Si puo' anche avere un datamodule custom, che permette di creare delle sottoclassi partendo da uno schema standard di dati e usare tali sottoclassi per le proprie mappe reali (con specifiche modifiche nei datamoduli derivati) e cosi' via.

(Un esempio di cio' potrebbe essere quello di impostare il proprio database o anche un oggetto sessione in un datamodule custom, e quindi derivare altri datamoduli da quello senza dover impostare nuovamente la propria sessione e gli oggetti dati!)

Questo documento ha gia' raggiunto una certa lunghezza, e piuttosto che spendere molto tempo spiegando in dettaglio i datamoduli, preferisco parlarne in qualche situazione dove si lavora con piu' di una tabella o si sta impostando del codice abbastanza complesso (come per esempio un evento canAppend o simili) ed e' molto meglio usare un datamodule ed incapsulare tutto il codice in esso, cosi' se e' necessario usarlo in un'altra form, si puo' risparmiare una gran quantita' di lavoro. Usa molto i datamoduli. Essi renderanno la tua vita di sviluppatore molto piu' facile.

Una nota, tuttavia, per aiutare nell'uso dei datamoduli:

Un datamodule non sa che cosa e' una "form" (o un report), cosi' come gli altri oggetti data non sanno che cosa e' una "form". Questo significa che non si puo' usare codice come il seguente dentro un datamodule ( si otterra' un errore del tipo "form" non trovata o qualcosa di questo tipo):

form.entryfield1.value := "myvalue"

Quando si inserisce un datamodule in una form, si sta in realta' ponendo un oggetto "datamodRef" nella form, che ha una proprieta' "ref ", che punta al datamodule reale. La ragione di cio' sta nel fatto che si puo' usare lo stesso datamodule, nello stesso tempo, su multiple form (o reports) -- come puo' il datamodule stesso sapere quale form o report e' il suo "parent" ? Se ci si riferisce a "form" nel datamodule come potrebbe quest'ultimo sapere quale form (o report) si intende?

E' difficile abituarsi a questa cosa, giacche' la maggior parte degli oggetti contenuti in una form o report capiscono a che cosa essi appartengono.

E' possibile, sebbene non sia una buona idea, riferirsi all'entryfield di una form da dentro un rowset contenuto da una query, contenuto da un datamodule, con queste linee:

// this = rowset

// parent1 = query

// parent2 = datamodule

// parent3 = connector (si veda OODML.HOW di A.Katz - N.d.T.)

// parent4 = form

this.parent.parent.parent.parent.entryfield1.value ...

La ragione del perche' non e' una buona idea e' che, se si e' decisi ad usare lo stesso datamodule in un report, non esiste un oggetto entryfield nel report. Si puo' desiderare di usare il datamodule su una differente form --- il nome dell'entryfield e' sempre lo stesso nelle varie mappe ?

Sommario

Questo documento non ha avuto l'intenzione di essere esaustivo per gli sviluppatori, ma piu' che altro e' stato creato affinche' gli sviluppatori nuovi al Visual dBase e/o nuovi al modello OODML del Visual Dbase 7 familiarizzino con gli oggetti Dati . Io spero che quello che ho scritto qui sia impiegato in maniera appropriata dove meglio la potenza di questi strumenti si ritenga possa essere applicata e che si possano quindi migliorare le proprie applicazioni basate su questa nuova conoscenza.

Vi sono molti riferimenti ad altri documenti presenti nel sito web dell'autore, questi documenti possono essere trovati a:

http://www.mindspring.com/~hirschv/dbase/dbase.htm

In piu', non posso che suggerire, in maniera decisa, che si legga anche, se non lo si e' gia' fatto, l'OODML.HOW di Alan Katz, che copre molta della teoria del modello ad oggetti dei dati in Visual dBase 7.

EoHT: BEGDATA.HTM -- March 15, 1999 -- KJM (traduzione in italiano di Santo Lo Galbo - 30 luglio 1999)