Sisteme de Baze de Date Relationale

1. INTRODUCERE

Informația este o noțiune de largă generalitate și reprezintă traducerea legăturilor cauză-efect din lumea reală. Pentru a utiliza corect această noțiune este necesar să se facă distincția între informații și date.

Informația trebuie privită ca o triadă a elementelor: entitate, atribut, valoare.

Entitatea formează obiectul informației și este complet definită doar dacă se iau în conșiderare toate atributele sale alături de valorile lor. Atributul este o proprietate a entității. Valoarea este o măsură a proprietății sau atributului asociat entității.

Datele constituie reprezentarea șimbolică a informațiilor într-o formă convențională, convenabilă unei comunicări. Ele au o interpretare și sunt prelucrate de om direct sau cu ajutorul calculatorului.

Metodele și tehnicile de organizare a datelor au evoluat în cadrul procesului de perfecționare a sistemelor informațice, fiind determinate de:

creșterea continuă a complexității activităților, care a condus la creșterea volumului de informații generate și prelucrate;

creșterea ritmului de dezvoltare a societății, care a determinat ca dimensiunea timpului de răspuns a sistemelor infomatice la cererile de informații să devină unul din criteriile de apreciere a gradului de organizare a datelor și, respectiv, a eficienței sistemelor informațice;

evoluția mijloacelor de culegere, transmitere și prelucrare a datelor.

Prima etapă a fost organizarea datelor în “fișiere pe aplicații” când proiectanții sistemelor informațice gestionau în mod izolat fișiere în vederea rezolvării problemelor particulare ale unui anumit departament.

A doua etapă se caracterizează prin separarea nivelului logic de organizare a datelor de cel fizic, utilizându-se fișiere organizate indexat sau aleator.

Cerințele complexe impuse sistemelor informațice moderne au creat necesitatea ca mai mulți utilizatori să aibă acces la aceeași colecție de date.

Utilizarea metodelor clasice de gestionare a datelor din fișiere duce la o creștere a redundanței datelor și o creștere a timpului de răspuns. În aceste condiții au apărut fișierele integrate sau sistemele de fișiere ( etapa a treia ).

Trecerea la fișiere integrate nu a rezolvat problema independenței programelor de aplicație de modul de organizare a datelor. Soluția a fost detașarea din programul de aplicații a descrierii fișierelor și a legăturilor dintre ele. Se ajunge astfel la primele bănci de date ( etapa a patra, care marchează un salt calitativ în organizarea datelor ).

O bancă de date este formată din:

baza de date, colecție de date aflate în interdependență, împreună cu descrierea lor;

un sistem de gestiune a bazei de date ( SGBD ) – un set de programe și proceduri specializate, destinate gestiunii și prelucrării complexe a datelor din baza de date;

un set de proceduri manuale și automate – specifice domeniului pentru care se organizează baza de date, precum și reglementările administrative destinate bunei funcționări a întregului sistem.

O bază de date este deci o colecție de date creată pentru a satisface mai mulți utilizatori, asigurând o redundanță minimă, o independență a programelor față de date, o optimizare a structurilor fizice care vor fi ignorate cu totul de utilizatori, o protecție a datelor memorate.

Avantajele organizării în baze de date sunt :

independența datelor memorate – asigurată de separarea nivelului de descriere a datelor de nivelul de utilizare a lor; astfel asigurându-se și integritatea programelor de aplicație la schimbările ce au loc în baza de date;

nivelul redus de redundanță – redundanța devine un fenomen controlabil;

securitatea datelor – se pot aplica restricții în ceea ce privește accesul neautorizat la date în vederea extragerii sau distrugerii unor date cu caracter confidențial;

integritatea datelor – asigurarea corectitudinii datelor în orice moment al functionarii sistemului;

facilități de utilizare a datelor fără ca utilizatorii să cunoască în întregime conținutul bazei de date;

accesarea bazei de date din diferite noduri ale rețelei de către utilizatori diferiți.

Oferta bogată de pachete de gestiune care permit gestionarea unor date foarte complexe în condiții de eficiență maximă, asigurând în plus utilizatorilor programatori instrumentele necesare concepției programelor lor, dar și utilizatorilor neinformaticeni o interfață “prietenoasă”.

2. BAZE DE DATE RELAȚIONALE

Denumirea acestor baze de date provine de la tipul de model utilizat în organizarea lor – modelul relațional, ale cărui nume și metode provin, la rândul lor, de la noțiunea matematică de relație.

O bază de date relațională este o colecție de date stocate în fișiere, numite tabele. Programul dBASE ( ca și toate celelalte SGBD-uri din aceeași familie ) au la baza teoria algebrelor relaționale, dar identifică notiunea de relație cu cea de tabel. Fiecare tabel este conectat cu cel puțin un alt tabel prin intermediul unui câmp comun care definește relația. Pentru a discuta despre structura relațională a datelor este necesară cunoașterea câtorva termeni: domeniu, relație, atribut, schemă a unei relații.

Domeniul este un ansamblu de valori caracterizat printr-un nume; se poate defini explicit prin enumerarea tuturor valorilor lui sau implicit prin precizarea proprietăților pe care le are domeniul respectiv.

Se numește produs cartezian al mulțimilor D1,D2,…,Dn finite și nu neaparat distincte, mulțimea tuplurilor (v1,v2,…,v n), unde v1,v2,…,v n aparțin respectiv mulțimilor D1,D2,…,Dn .

Relația este un subansamblu al produsului cartezian al mai multor domenii, caracterizat de un nume și care conține tupluri cu o anumită semnificație (tuplul reprezintă exprimarea generală a unei mulțimi).

Exemplu: D1*D2*…*Dn <v1,v2,…,v n>

D1*D2*D3 <v1,v2,…,v3> <”Maria”,F,45>

<”Vasile”,B,47>

Atributul reprezintă unitatea fundamentală a unei baze de date relaționale și se mai numeste câmp. Este dată de coloana unei tabele de date și se caracterizeaza printr-un nume; sunt elemente individuale de informație și se folosesc pentru a crește flexibilitatea datelor.

Fiecare coloană din tabelul de mai sus definește un câmp distinct. Pe toate liniile, informațiile din aceeași coloană au aceeași semnificație. De exemplu, numele unei persoane este un câmp, varsta este alt câmp, iar sexul este al treilea. Dacă se dorește stocarea unor informații suplimentare, fiecare informație individuală constituie un câmp. Pentru fiecare persoană înregistrată în tabel există mai multe câmpuri care o individualizează. Luate împreună, aceste câmpuri definesc o înregistrare. În general înregistrările se prezintă sub formă de linii.

Tabelul descrie o grupare de un nivel mai înalt decât o înregistrare, cuprinzănd o colecție de înregistrări. Presupunând că avem un tabel asemănător care conține informații despre o categorie de persoane alese după un anumit criteriu, aceste două tabele au un element comun – numele persoanei.

Combinația acestor două tabele și a relației dintre ele constituie un exemplu simplu de bază de date relațională.

Schema unei relații este compusă din numele relației urmat de lista atributelor și domeniile asociate fiecărui atribut.

Relație ( A: D1, A: D2, …,A: Dn )

Persoana ( Nume:D1,Sex: D2,Varsta: D3)

Schema unei relații se mai numeste și intensia relației și reprezintă o expresie a proprietăților comune și invariante ale tuplurilor care compun relația, rămânând neschimbată atât timp cât este folosita relația. Extensia unei relații poartă numele de relație de bază și este ansamblul tuplurilor care compun la un moment dat relația (mulțimea înregistrărilor existente la un moment dat într-un tabel ), fiind stocată fizic în spațiul asociat bazei de date.

2.1. DEFINIREA BAZELOR DE DATE, A TABELELOR ȘI

A INDECȘILOR

Crearea tabelelor pentru o aplicație

Dacă se urmăreste ținerea evidenței împrumuturilor dîntr-o biblioteca de CD-uri, este necesar sa se creeze o lista provizorie cu informațiile care sunt primite la efectuarea unui imprumut :

data imprumutului;

numele persoanei care a facut imprumutul;

adresa persoanei care a facut imprumutul;

lista CD-urilor imprumutate de o anumita persoana;

lista tuturor CD-urilor imprumutate;

Această listă utilizează mai multe categorii de date evidente pentru stocarea informațiilor referitoare la un imprumut. Prima categorie priveste informațiile referitoare la persoana care face împrumutul. Cea de a doua categorie ține evidenta informațiilor comune tuturor împrumuturilor, însa nu specifice CD-urilor individuale comandate. Această categorie poate să conțină data efectuării împrumutului și numărul CD-urilor împrumutate. A treia categorie conține detalii despre împrumut. În aceasta categorie se poate planifica câte o înregistrare sau mai multe pentru fiecare CD, care să conțină detalii referitoare la descrierea conținutului acestuia.

Stabilirea categoriilor de date necesare

Pentru o evidență cât mai riguroasă, este necesar să se rețină cât mai multe date referitoare la client. Astfel, ar fi indicat să se cunoască și locul de munca al acestuia, numărul de telefon etc. Simpla păstrare a numelui persoanei care a efectuat un împrumut s-ar putea să nu fie cea mai facilă metoda de a regăsi fișierul dacă se cunoaște doar numele. De aceea, trebuie să fie despărțit într-un câmp prenume și un câmp nume. În mod similar, adresa este compusă din una sau mai multe linii reprezentând strada, blocul, apartamentul, orașul etc. Fiecare element trebuie păstrat într-un câmp distinct. Chiar și numărul de telefon s-ar putea să nu fie suficient pentru clienții care au numere de interior.

Ceea ce trebuie facut într-o astfel de situație se numește atomizarea informațiilor referitoare la client. Fiecare atom definește un singur element care individualizează clientul. Rezultatele atomizării pot fi cele din lista următoare:

ID (un identificator unic pentru fiecare utilizator) ;

locul de muncă (poate fi și departamentul în cadrul unei firme) ;

numărul de telefon ;

interior (număr în cadrul centralei) ;

data ultimului împrumut.

Denumirea fiecărei date individuale

Pentru fiecare dată individuală trebuie să se stabilească un nume de câmp. În mod traditional, FoxPro limitează lungimea numelor câmpurilor la 10 caractere. În schimb, în Visual FoxPro, se pot defini nume de câmpuri cu o lungime de până la 128 de caractere, însă numai atunci când câmpul este definit într-o bază de date. Întrucât initial se definește un tabel de sine statator, numit tabel liber, trebuie respectată limita de 10 caractere.

În versiunile FoxPro anterioare, au fost create numeroase convenții de denumire pentru a face programele mai lizibile. Ele diferențiază variabilele dupa tip, domeniu și după faptul că sunt variabile de memorie sau câmpuri din tabele. Una dintre metodele uzuale definește câmpurile unui tabel ca începând cu un prefix format din două caractere, urmat de un caracter subliniere. Acest prefix identifică baza de date și este unic în toată aplicația. Restul de șapte caractere pot fi orice identificator unic din tabel. Câmpurile similare din tabele distincte pot avea același identificator de șapte caractere.

În cadrul acestei conventii de denumire, variabilele de memorie incep și ele cu doua caractere – primul reprezinta domeniul, iar al doilea tipul variabilei. Al treilea caracter poate fi și de aceasta data un caracter subliniere. Totuși, exista tendinta de a se renunta la caracterele de subliniere.

Printre avantajele utilizarii acestei conventii de denumire a variabilelor de memorie și a câmpurilor se numara urmatoarele :

posibilitatea de a foloși comenzile SCATTER și GATHER fara pericolul suprascrierii variabilelor din alt tabel sau al interferentei cu alte variabile de memorie ;

în instrucțiunile SQL poate fi omis prefixul care identifica tabelul;

câmpurile sunt usor de asociat cu tabelul de care aparțin;

domeniul și tipul variabilelor de memorie este identificat imediat;

câmpurile tabelelor nu se confunda cu variabilele de melelor nu se confunda cu variabilele de memorie în codul sursă.

Printre dezavantajele acestei conventii de denumire se numără următoarele :

transferul datelor intre tabele este mai complicat, necesitand instructiuni REPLACE individuale pentru fiecare câmp sau includerea unor clauze FIELD lungi în care sa fie enumerat fiecare câmp;

interogarea relaționala prin exemple nu poate identifica acele câmpuri aflate în relație (fara crearea unor relații permanente);

pierderea a doua sau trei caractere din zece ingreuneaza crearea unor nume de câmpuri sugestive;

Selectarea tipului de date adecvat pentru datele individuale

Stabilirea informațiilor care urmeaza sa fie salvate intr-un tabel reprezinta doar o prima etapa a definirii structurii unui nou tabel. În continuare trebuie analizata fiecare data individuală și stabilit Dacă trebuie stocată sub forma de șir de caractere, sub forma numerica, sub forma de data calendaristica sau sub forma unui alt tip de data. În plus, pentru câmpurile caracter și numerice, trebuie stabilit numarul de caractere necesare.

Crearea structurii tabelelor

Sa presupunem ca se urmareste crearea unui proiect. Ca și în cazul majoritatii functiunilor, FoxPro prevede mai multe metode pentru a face acest lucru. Se poate alege File, New din meniul principal, de exemplu. În urma acestei comenzi apare caseta de dialog New. Se selecteaza Project drept tipul fișierului și se executa clic pe New File, dupa care fișierului i se atribuie un nume.

În momentul crearii unui proiect, FoxPro il deschide automat. Proiectele au cadre de pagina. Fiecare cadru reprezinta un alt tip de fișiere, tip indicat de etichetele din partea superioara a paginii. Pentru a selecta o pagina se executa clic pe eticheta corespunzatoare. Pentru a crea un tabel se executa clic pe eticheta Data. Se creeaza un tabel liber selectand FreeTabels și executând clic pe New.

În continuare, VFP solicita un nume de fișier, de data aceasta pentru tabel. FoxPro va afisa caseta de dialog Table designer. Acest formular are un obiect cadru de pagina cu doua pagini. Prima pagina definește structura tabelului, iar a doua definește indecșii. Pentru a defini structura tabelului, trebuie introduse informațiile definite anterior, însoțite de tipurile câmpurilor, lățimile și numarul de zecimale. Ultima coloana a acestei structuri stabileste Dacă câmpul curent accepta valori nule. Conform exemplului de mai sus, fiecare persoana care poate efectua imprumuturi din baza de CD-uri este identificata printr-un indicativ (ID) unic.

Modificarea structurii tabelelor

Este de așteptat ca, pe durata de viață a unui proiect, să fie necesară modificarea structurii unui tabel. Amploarea unei modificari poate fi clasificata dupa cat de mult se schimba fișierul tabel și fișierele index. De exemplu, adaugarea unui câmp este o modificare minora, deoarece nu are nici un impact asupra câmpurilor existente – deși necesită rescrierea intregului fișier DBF. Redenumirea unui câmp reprezinta și ea o modificare minora: de obicei, nu se întampla nimic altceva decat modificarea antetului fișierului DBF. În schimb, Dacă se redenumeste un câmp care apare intr-un index, trebuie realizata și actualizarea indexului sau a etichetei. Eliminarea câmpurilor, atat timp cat nu sunt parte a unui index sau a unei etichete, necesita rescrierea intregului fișier DBF, ceea ce poate duce la pierderea datelor. Atunci cand se schimba tipul unui câmp, FoxPro incearca sa converteasca datele la noul tip, însă este posibil sa distruga automat datele dacă nu știe ce sa faca sau atunci când conversia nu are sens.

Indecșii structurali și nestructurali

Programul FoxPro permite foloșirea indecșilor structurali și nestructurali, numiti și indecși compuși. Acestia sunt fișiere index speciale, care pot contine definitiile mai multor indecși intr-un singur fișier fizic. Astfel, se pot stoca intr-un singur fișier definitiile tuturor indecșilor asociati unui fișier DBF, înlaturandu-se probleme de tipul găsirii unor pointeri de index nesincronizati sau neglijarii deschiderii unor fișiere index.

Definirea indecșilor normali și a indecșilor unici

Definitiile indecșilor încep cu numele etichetei, în stanga, urmat de tipul indexului, expresia etichetei și un filtru. Sagetile din stânga numelor indică dacă indexul este în ordine ascendentă (săgeata în sus) sau descendentă (sageata în jos)

Tipul de index Regular (normal) indică faptul că FoxPro stocheaza în index valoarea generala de expresie a indexului pentru fiecare linie a tabelului. Dacă mai multe înregistrări au aceeași expresie, FoxPro stocheaza expresia de mai multe ori, cu pointeri distincți pentru fiecare înregistrare.

Un alt tip de index este Unique (unic). În cazul tipului unic sunt incluse numai valorile unice ale indexului. Dacă mai multe înregistrări generează aceeași valoare a expresiei indexului, este stocată numai prima întâlnită. Dacă se definește un index unic, s-ar putea ca nu toate înregistrările sa fie incluse în index.

Definirea cheilor candidat și a cheilor primare

Al treilea tip de index, numit candidat (Candidate), creeaza un index unic, însă include fiecare înregistrare din tabel. Indecșii candidat interzic prezenta valorilor dublate ale expresiei indexului pentru oricare doua înregistrări din tabel.

Uneori, este posibil ca un singur tabel să aiba mai multe câmpuri care identifica în mod unic fiecare înregistrare. Fiecare asemenea index este un index candidat și o potentiala cheie primara. Cu toate acestea, fiecare tabel poate avea o singura cheie primara. Deseori cheile primare creeaza relații intre mai multe fișiere și servesc drept valori de cautare intr-un tabel la care se face referire.

Indexarea după expresii complexe

FoxPro nu limiteaza expresiile indecșilor la un singur câmp. Practic orice combinatie de câmpuri poate fi folosita drept expresie a unui index.

Crearea unei baze de date

În Visual FoxPro o baza de date este o colectie de tabele. Se poate lucra și cu tabele individuale, asa cum ar fi în vechiul stil FoxPro. Totuși, Visual FoxPro ofera cateva imbunatatiri semnificative atunci cand este nevoie de o sortare a tabelelor aflate în baza de date.

Pentru început se poate crea un container baza de date pentru stocarea tabelelor. Comanda urmatoare creeaza și denumește o nouă bază de date într-o singura etapă:

CREATE DATABASE BIBLIOTECA

Dacă exista una sau mai multe baze deschise, baza de date curentă este afisata într-o caseta, iar lista derulanta permite trecerea la alta. Într-un program se pot obține numele și calea bazelor de date curente cu funcția DBC() și se poate schimba baza de date curentă cu instrucțiunea SET DATABASE TO. Pentru a determina numele și calea tuturor bazelor de date deschise, se foloseste funcția DATABASE(). Aceasta creează un masiv bidimensional, primul element fiind numele bazei de date, iar al doilea fiind calea. Atunci când se adaugă tabele într-o baza de date, ele apar în fereastra Database Designer. Atunci când se adauga mai multe tabele apar bare de derulare. Pentru fiecare tabel sunt afisate câmpurile, urmate de indecșii tabelului. O cheie micuta, situata în fata numelui unui index, identifica indexul primar. Relațiile dintre tabele sunt ilustrate cu linii de conectare. Pentru a consulta un tabel, se executa dublu clic pe el.

Adaugarea tabelelor existente la baza de date

Pentru a adauga un tabel existent la baza de date curenta, se executa clic pe butonul Add Table din bara cu instrumente Database Designer. Definitiile tabelelor se pot trata ca orice fereastra, deci pot fi trase și redimensionate dupa dorinta. Pentru modificarea oricarui tabel, acesta se selecteaza și se executa clic pe butonul Modify Table din bara cu instrumente Database Designer.

Una dintre primele modificari care se pot face este redenumirea câmpurilor folosind nume lungi de câmpuri, însă odata facut acest lucru numele lungi trebuie folosite intotdeauna. Nu se pot folosi nici numele mai scurte stocate în fișierul DBF, nici numele trunchiate la zece caractere. Spatiile nu sunt permise în numele câmpurilor.

Se pot, de asemenea, adauga reguli de validare la nivel de câmp în caseta de dialog Table Designer. Se poate folosi orice expresie logica atunci cand se definește o regula de validare. Se poate apela chiar o functie pentru testele care sunt prea complexe pentru a fi exprimate într-o singura instructiune. Singura restrictie este ca functia sa returneze .T. sau .F. Regulile de validare a câmpurilor sunt declansate atunci cand se incearca parasirea câmpului sau când valoarea câmpului se modifica datorită unei instrucțiuni INSERT sau REPLACE.

Pentru fiecare câmp al tabelului se poate adauga o valoare prestabilita. De exemplu, pentru a declara data curenta a sistemului drept valoare prestabilită, se plaseaza functia DATE() în caseta de text Default Value. Rezultatul expresiei pentru valoarea prestabilita trebuie sa fie compatibil ca tip cu câmpul însuși, în caz contrar FoxPro generand o eroare. FoxPro plaseaza valoarea prestabilita în câmpul tabelului ori de cate ori se adauga o noua înregistrare în tabel.

FoxPro utilizează valorile titlurilor drept anteturi ale coloanelor atunci cand se afiseaza tabelul în fereastra Browse sau Edit. Dar titlul se poate defini și pe baza altui câmp sau a unei variabile, cea mai frecventa optiune fiind însă introducerea unui text simplu în caseta de text Caption.

Chei primare și chei candidat

Este de retinut faptul ca numai un index care indeplineste conditiile pentru a fi index candidat poate fi numit index primar. Aceasta inseamna ca expresia indexului face referire la fiecare înregistrare din tabel cu o valoare unica. Indexul primar se foloseste pentru a forma relații cu alte tabele.

Testarea cheilor primare și a cheilor candidat are loc atunci cand VFP actualizeaza înregistrarea. De aceea este posibil sa nu se primeasca un mesaj de eroare dacă valoarea cheii nu este unica decat în momentul părăsirii înregistrarii.

Relații permanente

Relațiile permanente definesc relațiile între tabele și sunt stocate în caseta de dialog Database Designer. Visual FoxPro le foloseste automat la fiecare deschidere ulterioara a tabelel. Aceasta caracteristica este utila mai ales pentru crearea tabelelor de cautare, a validarilor și a mediului de date al formularelor și rapoartelor.

Relațiile permanente sunt numite asa prin contrast cu relațiile temporare, create cu comanda SET RELATION. Motivul pentru care relațiile create cu aceasta comanda sunt temporare este ca FoxPro le dizolva atunci cand se paraseste programul sau cand se lanseaza comanda SET RELATION fara parametri. Relațiile permanente se mentin de la o rulare la alta a aplicațiilor.

Pentru a defini o relație se executa clic pe numele unui index dintr-un tabel și se trage peste un index din alt tabel. FoxPro va afisa caseta de dialog Edit Relationship, în care FoxPro completeaza automat numele. Se pot defini relații de tip unu-la-unu și relații de tip unu-la-mai-multe. FoxPro aplica o serie de reguli simple atunci când definește tipul relației. În primul rând presupune că tabelul initial se află în partea stângâ a relației și trebuie să fie un index candidat sau un index primar. Dacă în continuare se realizeaza o conexiune cu un index primar sau cu un index candidat din al doilea tabel, FoxPro știe că este vorba de o relație unu-la-unu, deoarece acestia sunt indecși unici, care include fiecare înregistrare din tabel. Conectarea la orice alt index (normal sau unic) permite existenta mai multor înregistrări în partea dreapta a relației; prin urmare FoxPro presupune ca este vorba de o relație una-la-mai-multe. Este de retinut faptul ca un index unic nu interzice prezenta mai multor înregistrări avand aceeași valoare a indexului, dar pastreaza un pointer către prima.

Pentru a rupe o relație care nu mai este necesara sau este definita incorect, se executa clic pe ea și se apasa tasta Delete.

Modificarea proprietăților tabelelor prin program

În trecut modificarea proprietăților unui tabel dintr-un program era o operatie dificilă, care necesita ca programul sa creeze o noua copie modificata a tabelului, dupa care sa copieze datele din vechiul tabel în cel nou. Cu Visual FoxPro aceasta sarcina a devenit mai simplă prin adaugarea a doua comenzi noi, ALTER TABLE și ALTER COLUMN. Aceasta posibilitate se refera numai la tabelele care fac parte dintr-o baza de date.

CONCEPTE AVANSATE DE GESTIONARE A BAZELOR DE DATE

Factorul care are influenta cea mai mare asupra succesului unei aplicații de baze de date este proiectarea propriu-zisă a bazei de date. Modul în care se organizează datele individuale într-un tabel și modul în care se creeaza relații între tabelele unei baze de date reprezinta temelia aplicatiei.

Normalizarea datelor

Cel mai important lucru care trebuie facut atunci când se începe o nouă aplicație este proiectarea structurii tabelelor. Un set de tabele bine concepute, pe lângă faptul că permite atingerea obiectivului aplicației, oferă flexibilitatea de a răspunde la probleme care nu fusesera anticipate. În timp ce, în cazul unei structuri nenormalizate, generarea rapoartelor ar fi necesitat programarea manuala, greoaie, în cazul unei structurari corecte, ele se scriu aproape de la sine cu generatorul de rapoarte.

În general, structura datelor asigură succesul sau determină eșecul unei aplicatii mai mult decât orice alta caracteristica individuală. Visual FoxPro se bazeaza pe modelul de baza de date relaționala, propus initial de E.F. Codd în 1970. El și-a bazat modelul pe principiile matematice care guverneaza teoria multimilor relaționale. El a demonstrat ca prin respectarea catorva reguli foarte stricte, care definesc crearea multimilor, datele se pot manipula cu ușurință. Aceste tehnici au devenit cunoscute sub numele de normalizarea datelor.

În primul rând, întreaga teorie referitoare la bazele de date relaționale este axata pe conceptul definirii relațiilor intre fișierele conținând tabele plate cu ajutorul câmpurilor cheie. Cu cat exista mai multe tabele, cu atât programului FoxPro îi sunt necesare mai multe relații pentru conectarea lor. Teoria mulțimilor nu impune ca fiecare tabel sa fie conectat direct cu toate celelalte tabele. Totuși, întrucat fiecare tabel este conectat cel putin cu un alt tabel, toate tabelele din baza de date se afla în relație directa sau indirecta.

Pentru a analiza conceptele privind normalizarea, acest paragraf studiaza inceputul procesului de dezvoltare a aplicatiei, imediat dupa stabilirea datelor necesare.

Dependente funcționale

Presupunand ca au fost stabilite deja care sunt câmpurile de date necesare, urmatoarea etapa consta în impartirea lor în tabele. Singura metoda de a stabili ce câmpuri trebuie incluse în fiecare tabel este prin intermediul analizei dependentei functionale.

Dependenta functionala definește relația dintre un atribut sau un grup de atribute ale unui tabel și un alt atribut sau grup de atribute ale altuia. În cazul de fata, atributele se refera la câmpuri. Deci, trebuie vazut ce câmpuri depind de alte câmpuri. Se vor grupa în același tabel acele atribute care au aceeași dependenta. Practic, numarul dependentelor functionale determina numarul de tabele necesare.

Dacă se urmeaza aceasta metoda de grupare a câmpurilor, tabelul rezultant va fi deja foarte aproape de o forma normalizata. Totuși, va trebui sa se verifice Dacă sunt indeplinite cel putin primele trei reguli ale datelor normalizate:

Prima forma normala : elimina câmpurile care se repeta și valorile ne-atomizate.

A doua forma normala : impune ca fiecare coloana sa fie dependenta de fiecare parte a cheii primare

A treia forma normala : impune ca toate câmpurile non-primare sa depinda numai de câmpurile primare.

Rațiuni pentru încălcarea regulilor de normalizare

Regulile de normalizare nu sunt legi; ele sunt simple linii directoare care ajuta la evitarea crearii unor structuri de date care limiteaza flexibilitatea aplicatiei sau ii reduc eficienta. Exemplul care urmeaza reprezinta o situație în care încălcarea regulilor de normalizare ar putea avea sens.

Sa presupunem ca trebuie conceput un sistem de gestiune a unei biblioteci care să impiedice un abonat sa imprumute mai mult de cinci CD-uri simultan. S-ar putea concepe acest sistem prin normalizarea fișierului care tine evidenta CD-urilor imprumutate. Acesta ar trebui sa verifice ca exista cel mult cinci înregistrări pentru fiecare abonat. În schimb, o singura înregistrare cu cinci câmpuri, cate unul pentru fiecare CD, ar putea simplifica dezvoltarea aplicatiei (evident, o solutie alternativa ar fi adaugarea unui câmp în tabelul principal de abonati care sa calculeze numarul de CD-uri imprumutate de fiecare abonat).

Caracteristici avansate ale dictionarului de date Visual FoxPro

Una din caracteristicile avansate a fost deja mentionata: dictionarul de date Visual FoxPro cu capacitatea sa de a atribui nume de câmpuri de 128 de caractere. Deși aceasta caracteristica reprezinta o imbunatatire remarcabila fata de limita de 10 caractere a tabelelor libere, ea are dezavantajul ca este dificila trecerea la numele de 10 caractere, o data ce s-a folosit nume de câmp de 128 de caractere.

1. Validari la nivel de câmp

O alta caracteristica importanta este adaugarea regulilor de validare la nivel de câmp și a mesajelor de validare. Visual FoxPro utilizează automat regulile de validare atat în mediul interactiv, cat și în formulare fara sa fie necesar sa se scrie cod sursa suplimentar. Acest tip de validare se mai numeste și validare declarativa, prin contrast cu validarea procedurala, care se bazeaza pe scrierea de cod sursa în proceduri sau în functii pentru validarea modificarilor efectuate asupra câmpurilor.

Visual FoxPro declanseaza regulile de validare la nivel de câmp ori de cate ori se modifica valoarea unui câmp și se incearca parasirea câmpului. De asemenea, Visual FoxPro utilizează regulile de validare și în unele comenzi (APPEND, BROWSE, UPDATE etc).

2.Câmpuri cu valori prestabilite

Se poate folosi definitia extînsă a tabelului pentru a furniza o valoare prestabilita pentru un câmp. Visual FoxPro o foloseste atunci cand se adauga o noua înregistrare în tabel. Valorile prestabilite servesc mai multor scopuri:

impiedica lasarea unui câmp necompletat ;

furnizeaza cea mai probabila valoare;

asigura faptul ca testele de validare nu vor esua pentru simplul fapt ca un utilizator sare un câmp.

3.Titluri și comentarii

Câmpurile titlu pot contine pana la 128 de caractere. Ele sunt afisate drept anteturi ale coloanelor atunci cand se deschide un tabel în fereastra Browse.

Visual FoxPro nu utilizează nicaieri câmpul Comment. Acest câmp este pus la dispozitia utilizatorului pentru ca acesta sa poata explica semnificatia câmpului, sa justifice o anumita valoare prestabilita sau sa arate cum functioneaza validarea câmpului.

4.Validare la nivel de înregistrare

O regula de validare din caseta de dialog Table Properties reprezinta o validare la nivel de înregistrare. Visual FoxPro declanseaza aceasta regula atunci cand se modifica valoarea unui câmp din înregistrare și se incearca trecerea la alta înregistrare. Atunci cand se foloseste validarea la nivel de câmp, codul sursa de validare nu poate modifica nici un câmp din înregistrarea curenta și nici nu poate deplasa indicatorul de înregistrare. În schimb, poate compara valoarea unui câmp cu valoarea altuia.

Validarea înregistrării poate fi mai complexa decat o expresie. Poate fi o functie definita de utilizator care va apela codul sursa de validare salvat în baza de date sub forma unei proceduri rezidente. Orice apel al unei expresii sau functii de validare trebuie sa returneze un rezultat logic. Dacă este returnata valoarea.F., Visual FoxPro pastreaza indicatorul de înregistrări la aceeași înregistrare și nu salveaza modificarile facute asupra ei. În plus, afiseaza textul de validare.

5.Declanșatori

Urmatoarele trei optiuni din caseta de dialog Table Properties se numesc declansatori. Visual FoxPro îi execută atunci când se insereaza, actualizeaza sau elimina o înregistrare din tabel. Ca și în cazul regulilor de validare a înregistrărilor, trebuie pastrat codul sursa al declansatorilor în baza de date sub forma unor proceduri stocate. Se pot folosi declansatorii pentru calcule sau validari suplimentare atunci cand se efectueaza oricare dintre aceste trei operatii. Exista totuși cateva lucruri care nu se pot face cu ajutorul declansatorilor și anume :

nu se poate deplasa indicatorul de înregistrări în zona de lucru curenta;

nu se poate modifica valoarea nici unui câmp din înregistrarea curenta;

nu se poate inchide zona de lucru curenta sau deschide un alt fișier în aceeași zona de lucru.

6. Integritate referențială

În general, integritatea referentiala definește operatiile permise intre tabele conectate prin relații. Premisa de baza este ca valorii unei chei externe din tabelul parinte trebuie sa-I corespunda o cheie de cautare sau o cheie primara intr-un alt tabel (numit tabel fiu). Integritatea referentiala trateaza înregistrările care nu indeplinesc aceste criterii drept invalide.

PARTAJAREA DATELOR ÎN RETEA

Una din principalele probleme ale procesarii datelor este cea ridicata de conflictele care survin atunci cand doi utilizatori incearca sa acceseze simultan aceleași date. În multe aplicatii, cel care salveaza ultimul modificarile castiga jocul actualizarii. Datele acestei persoane reprezinta modificarile finale și definitive efectuate asupra bazei de date, în detrimentul oricaror actualizari anterioare.

Sistemul Visual FoxPro al firmei Microsoft protejeaza într-o oarecare masura acest tip de activitate permitand utilizatorului sa foloseasca o metoda (fie automata, fie explicita) de blocare a înregistrării sau a tabelului inaitea actualizarii datelor. Atunci cand tabelul și înregistrarea sau înregistrările aferente sunt accesate, blocarea impiedica orice alt utilizator sa acceseze zona respectiva pana în momentul în care primul utilizator nu a terminat operatiile de editare și nu a parașit în bune conditii zona.

1. Coliziuni de fișiere, conflicte și blocări definitive

În locul utilizarii exclusive a datelor de catre un singur utilizator, informațiile pot fi partajate de un departament sau de un grup de utilizatori. Solutia uzuala este de a elimina datele de pe unitatea de disc locala și a le instala intr-un calculator server de fișiere la care au acces toti cei care au nevoie de fișierele respective. O alternativa o reprezinta partajarea hard-discului local. Prima abordare este cea mai uzuala, în schimb, retelele de tip ‘peer-to-peer’ devin din ce în ce mai populare.

Urmatoarea problema o constituie stabilirea modului în care vor fi gestionate conflictele electronice ivite atunci cand doua persoane incearca sa acceseze aceleași date, activitatea aceasta fiind cunoscuta sub numele de conflict de fișiere. Programele destinate sa functioneze intr-un mediu partajat trebuie sa posede un mecanism pentru evitarea consecintelor unor asemenea situatii.

Într-o aplicatie partajata, conflictele de fișiere survin atunci cand doi utilizatori incearca sa acceseze simultan aceeași înregistrare a aceluiași fișier. O aplicatie trebuie sa previna evenimente de asemenea natura prin arbitrarea conflictelor intre utilizatori.

Un eveniment destul de intalnit în mediile partajate este blocarea definitiva. Aceasta survine atunci cand un utilizator a blocat o înregistrare sau un tabel, dupa care incearca sa blocheze a doua înregistrare sau tabel care a fost blocata anterior de un alt utilizator. În același timp, al doilea utilizator incearca sa blocheze înregistrarea care a fost deja blocata de primul utilizator. În consecinta, ambele calculatoare vor ramane blocate, asteptandu-l pe celalalt utilizator sa incheie efectuarea modificarilor, ceea ce nu se va intampla niciodata.

Aceste paragrafe sugereaza crearea unei arhitecturi deschise, care sa permita tuturor utilizatorilor accesul liber la orice element din retea. Acest stil de gestionare a retelei, deși nu este intotdeauna acceptabil, este foarte utilizat.

Un pas inainte în directia urmatorului nivel de securitate sugereaza utilizarea unui nivel structurat de securitate a retelei, conform caruia anumitor utilizatori sa li se acorde privilegii.

2. Tipuri de blocaje

Atunci cand se dezvolta aplicatii multiutilizator pot sa apara doua tipuri de blocaje: de fișier și de înregistrare.

2.1. Blocarea înregistrărilor sau a fișierelor

În aplicatiile în care trebuie asigurat accesul mai multor utilizatori, trebuie avut în vedere ca accesul la date sa fie permis numai utilizatorilor care il solicita. Un blocaj de înregistrare, Dacă este corect aplicat, impiedica accesul în mod scriere al altor utilizatori în afara celui care a solicitat blocarea. Pe de alta parte, un blocaj de fișier blocheaza tabelul la nivel fizic, impiedicandu-I pe ceilalti utilizatori sa scrie date în tabel atat timp cat primul utilizator editeaza una sau mai multe înregistrări ale tabelului. Blocarea înregistrărilor și a fișierelor nu ii impiedica pe ceilalti utilizatori sa citeasca date din înregistrările sau fișierele blocate, ci interzice scrierea datelor.

Este de preferat blocarea înregistrărilor deoarece acestea interzic accesul doar la înregistrările individuale, nu la intregul tabel.

2.2. Blocari automate sau blocari manuale ?

Exista doua metode de blocare a datelor în ceea ce priveste protejarea datelor în raport cu operatiile de manipulare afișierelor : automata și manuala.

În funcție de necesități, blocarea fișierelor poate avea loc fie automat, fie prin intermediul unei metode manuale. FoxPro va incerca sa blocheze automat înregistrările atunci cand sunt utilizate anumite comenzi de actualizare a datelor. În tabelul urmator sunt date cateva dintre comenzile care blocheaza automat înregistrările:

În masura posibilului, este de preferat sa se foloseasca comenzi care blocheaza înregistrări individuale în locul celor care blocheaza intregul tabel. Aceasta afirmatie se bazeaza pe faptul ca se evIta supraincarcarea retelei cauzata de blocarea unui fișier și riscul ca fișierul sa fi fost deja blocat de alt utilizator. În Visual FoxPro, un fișier poate fi blocat numai Dacă nu contine înregistrări blocate.

Functiile de blocare manuala testeaza starea de blocare a unei înregistrări sau a unui tabel. Dacă în urma testarii se constata ca înregistrarea nu este blocata, înregistrarea (sau tabelul) va fi blocata și utilizatorul poate sa inceapa sa foloseasca fișierul. Pentru a bloca manual un tabel, trebuie folosita una din functiile LOCK(), FLOCK() sau RLOCK(). Dacă se foloseste una dintre aceste comenzi pentru a bloca o înregistrare sau un tabel, trebuie eliminate aceste blocaje de indata ce nu se mai utilizează înregistrarea sau tabelul.

3. Cum se procedeaza atunci când înregistrarea necesară este blocata ?

Când apare o astfel de situație, se va vedea mesajul de eroare ‘Record is în use by another’ și este necesar să se astepte cu efectuarea editarilor.

Atunci cand se editeaza câmpuri situate în tabele aflate în relație, înregistrările aferente sunt blocate pentru a evita dubla editare. În schimb, dacă înregistrarea curenta sau oricare dintre înregistrările corelate sunt blocate de alt utilizator, tentativa de blocare va eșua. Atunci când tentativa de blocare reușește, FoxPro permite editarea înregistrării. Blocajul este eliminat atunci când se trece la alta înregistrare, se activeaza alta fereastra sau se efectueaza o alta activitate.

INTRODUCERE ÎN PROGRAMAREA ORIENTATA PE OBIECTE

Majoritatea specialistilor sunt de parere ca modul actual de dezvoltare a codurilor procedurale este sortita pieirii. Printre rațiunile pe care se bazeaza o asemenea afirmatie sunt urmatoarele:

necesitatea de dezvoltare a unor aplicatii extrem de complexe;

necesitatea de reducere a intervalului de timp dintre conceptie și livrare;

necesitatea unei abordari grafice pentru comunicarea cu utilizatorii;

necesitatea de accesare a datelor dintr-o mare diversitate de formate și platforme;

proliferarea mediilor client/server;

necesitatea de a asigura utilizatorului un control sporit asupra aplicatiilor;

Toate aceste motive au exercitat o presiune imensa asupra metodelor de programare traditionala. A venit momentul trecerii la un nou model de programare – programarea orientata pe obiecte. Visual FoxPro se inscrie în acest model de programare pastrând însă legatura cu trecutul pentru a menține compatibilitatea cu toate aplicatiile FoxPro anterioare.

OBIECTE ȘI CLASE

Visual FoxPro extinde definiția obiectului față de versiunile anterioare ale programului FoxPro. Majoritatea elementelor care compun interfața FoxPro sunt obiecte: ferestrele, butoanele, câmpurile.

Un obiect poseda :

*proprietati, care identifica atributele fizice ale lucrurilor (pentru un buton de comanda dintr-un formular atribute pot fi : pozitia pe formular, latimea, inaltimea, culoarea, textul care eticheteaza butonul);

*metode, care sunt actiuni ce pot fi efectuate de obiecte (pentru un formular sunt două metode Open și Close)

CLASE DE BAZA

Visual foxPro prevede 28 de clase de baza predefinite, pe baza carora se pot crea noi obiecte. În tabelul urmator sunt enumerate clasele de baza ale limbajului Visual foxPro :

Visual foxPro împarte în continuare aceste clase de baza în clase container și clase control. O clasa container poate gazdui alte obiecte în interiorul ei. De exemplu, un formular apartine clasei container deoarece se pot plasa în interiorul sau alte obiecte, cum ar fi casete de validare, casete de editare, casete de text, linii și altel. Clasele control nu pot contine alte obiecte. O data ce se plaseaza un obiect control intr-un container, orice referire la obiectul respectiv trebuie sa contina și o referire la container.

De remarcat faptul ca, deși rapoartele contin obiecte cum ar fi etichete, câmpuri și forme, acestea nu sunt obiecte. Ele nu au proprietati, evenimente sau metode ca un formular. De altfel, nici raportul în sine nu este un obiect deoarece raportul sau obiectele pe care le contine nici nu trebuie sa urmeze noul model, bazat pe obiecte, pentru ca utilizatorii nu interactioneaza cu rapoartele.

Moștenire

Clasa de baza atribuie valori prestabilite unor proprietati. Practic, toate proprietatile unei clase de baza trebuie sa aiba valori prestabilite, chiar Dacă este vorba de șiruri vide.

Atunci cand un obiect este creat, el copiaza nu numai proprietatile, metodele și evenimentele clasei părinte, dar și valorile prestabilite. El mosteneste aceste informații. Se pot crea la infinit noi clase din cele deja existente, fiecare noua clasa creata mostenind toate elementele predecesoarei. Mai mult, unele obiecte pot avea mai multe clase parinte, mostenind toate proprietatile acestora.

Instanta

În dictionarul limbii engleze, instanta este definita ca fiind un caz sau un exemplar. Orice obiect creat este o instanta a clasei parinte. De aceea, procesul crearii obiectului se numeste instantiere. Dacă se creeaza o alta instanta a obiectului, ea va fi identica cu prima, cu exceptia titlului (titlul celei de a doua instante are un numar de secventa diferit de prima).

Incapsularea proprietatilor

Chiar dacă procedeele de mai sus creeaza doua forme apartinand aceleiași clase de baza, fiecare dintre ele este independenta de cealalta. Un aspect important este ca deși formele sunt independente, numele proprietatilor fiecareia sunt identice. Versiunile anterioare ale programului foxPro suportau numai doua tipuri de variabile – publice și private. Din pacate, nici unul din aceste tipuri nu este adecvat în cazul de fata. Obiectele necesită ca variabilele asociate proprietatilor sa fie locale instantei și, în același timp, sa poata fi apelate din exteriorul definitiei obiectului. Cu alte cuvinte, este necesar ca aceste variabile sa fie incapsulate în interiorul obiectelor. Prin urmare, se poate folosi același nume de proprietate în mai multe obiecte. Pentru a afisa orice instanta a unei proprietati, se foloseste sintaxa urmatoare :

? <nume obiect>.<nume proprietate>

Visual foxPro numeste acest tip de notatie – notatie cu punct. Ea asociaza proprietatile cu obiectele vizate deoarece este posibil sa existe mai multe obiecte active cu aceeași proprietate. Dacă se incearca afisarea unei proprietati fara a foloși numele obiectului, Visual foxPro va considera ca se doreste valoarea unui câmp al unui tabel sau a unei variabile de memorie. Dacă tabelul curent are un câmp cu numele respectiv sau dacă exista o variabila de memorie cu acest nume, Visual foxPro afiseaza valoarea. În caz contrar, afiseaza mesajul :

Variable ‘<nume proprietate>’ is not found.

Atribuirea mai multor pseudonime unui obiect

Numele unui obiect contine un pointer (o referinta) la o zona a memoriei unde este stocată informația propriu-zisa despre obiect. De aceea nu exista nici un motiv pentru a nu avea mai mult de o variabila cu același pointer. De exemplu, expresia urmatoare definește o a doua varibila care indica același formular indicat de formular1.

Formular2 = formular1

Formular2 nu este o alta instanta a clasei form. Este doar un alt nume ( un pseudonim ) pentru formular1.

Eliberarea obiectelor

Pentru a elibera ferestrele create cu comanda define window, se pot foloși în continuare comenzile traditionale. Pentru a elimina individual, se foloseste comanda RELEASE WINDOW <fereastra>; pentru a le elimina pe toate șimultan, se foloseste CLEAR WINDOWS.

Pentru a elimina un obiect formular, comanda RELEASE WINDOW nu va functiona decat dacă se stie numele formularului, nu titlul sau pseudonimul foloșit în locul numelui obiectului. În general, eliberarea numelui unui obiect elimina totodata și obiectul. Dacă însă au fost create mai multe pseudonime, comanda RELEASE elimina numai una dintre cele doua ferestre.Aceasta deoarece Visual foxPro elimina un obiect numai dacă se elibereaza toate referintele la el (pseudonimele), lucru care se poate face utilizand comanda

RELEASE ALL LIKE formular*

Incapsularea obiectelor

La fel ca și numele variabilelor, clasele de obiecte nu pot contine blancuri. De asemenea, utilizarea majusculelor și a literelor mici pentru denumirea ferestrelor și obiectelor, deși tine de preferintele fiecaruia, ar trebui sa respecte o coventie standard de denumire. Visual FoxPro este complet insensibil la majuscule.

Numele obiectelor, dupa cum s-a mentionat anterior, nu sunt obiectele propriu-zise, ci mai curand simpli pointeri către locatiile de memorie care stocheaza informațiile obiectelor. Se pot privi proprietatile unui control ca fiind elementele unui masiv. Pentru a face referire la orice element al unui masiv, este nevoie de numele masivului și de numarul elementului. În cazul de fata, numele obiectului este echivalentul numelui masivului, iar numele proprietatii identifica elementul. Atunci cand se plaseaza un obiect în altul se adauga pur și simplu un nou element la masivul primului obiect pentru a stoca pointerul la noul obiect. Deoarece numele obiectelor sunt pointeri la obiectul real, se poate face ca FoxPro sa parcurga ierarhia de pointeri pentru a gasi referinta obiectului de pe cel mai de jos nivel și pentru a o stoca separat.

Utilizarea codului pentru crearea subclaselor

În continuare se va arata ca exista o metoda mult mai flexibila pentru a crea obiecte ale claselor de baza.

1.Definirea unei subclase

O subclasa nu este un obiect ; poate fi privita mai degraba ca o copie a unui model principal folosit pentru crearea obiectelor. Se pot crea subclase din orice clasa de baza cu ajutorul comenzii DEFINE CLASS. Instructiunea urmatoare reprezinta o definitie completa, dar simpla, a unei subclase :

DEFINE CLASS TestWind AS FORM

END DEFINE

DEFINE CLASS creeaza o noua clasa bazata pe o clasa existenta, Form, și ii atribuie un pseudonim, TestWind. Acesta noua clasa este o subclasa. Totuși, aceste instructiuni par sa nu faca nimic. Ca și functia CREATEOBJECT, ele definesc ceva în memorie, însă doar atat. De aceea se foloseste functia de mai sus pentru a crea o instanta a noii clase. Aceasta va returna un pointer caruia I se va putea atrbui numele unei variabile. Pentru a crea un obiect apartinand noii clase TestWind, se apeleaza functia CREATEOBJECT. De data aceasta însă, în locul clasei de baza FORM numele clasei este numele noii subclase, TestWind.

Avantajul acestei abordari este ca se poate crea o aplicatie cu un aspect personalizat, cum ar fi spre exemplu existenta unor ferestre cu fondul galben și textul rosu. Aceste informații se pot incapsula în definitia noii clase. În continuare, orice formular creat folosind aceasta clasa mosteneste aceste culori.

O data cu trecerea anilor, specificarea culorilor a devenit mai complexa, fapt care se datoreaza posibilitatii monitoarelor de a lucra cu 16, 64, 256 sau chiar 16 777 216 de culori.

Iata de ce Visual FoxPro opteaza pentru o abordare stiintifica a problemei și definește culorile ca reprezentand amestecuri a trei culori primare: rosu, verde și albastru. De altfel, termenul RGB provine tocmai de la initialele acestor culori în limba engleza. Fiecare culoare primara are o valoare cuprînsă intre 0 și 255, reprezentand cantitatea din culoarea respectiva. Fiecare culoare afisabila este reprezentata ca o combinatie a valorilor celor trei culori primare.

De exmplu, specificarea valorii 0 pentru toate cele trei culori primare semnifica faptul ca nu se doreste nici una din aceste culori. Aceasta absenta a culorii creeaza negrul. În mod similar, specificarea valorii maxime (255) pentru fiecare culoare primara desemneaza culoarea alba.

2.Adaugarea unor noi proprietati în definitia unei subclase

Pentru a adauga noi proprietati în definitia unei subclase, este suficient sa se includa numele proprietatii imediat dupa instructiunea DEFINE CLASS , urmata de valoarea prestabilita. Deși se pot initializa valorile prestabilite ale proprietatilor folosind orice tip de variabila, nu se poate defini valoarea prestabilita foloșind o expresie. Nu exista nici o limita în privinta numarului de proprietati pe care le poate avea o clasa. Ca regula generala, Dacă nu se foloseste în mod explicit o proprietate prin intermediul unei metode, atunci aceasta nu iși justifica existenta.

3.Adaugarea controalelor intr-un container

Atunci cand se definește o noua clasa care deriva dîntr-o clasa de baza existenta, se pot adauga noi proprietati. Avand un formular cu mai multe controale elementare, necesare tuturor utilizatorilor și dorind adaugarea unor controale avansate, rezervate utilizatorilor experimentati inseamna ca este nevoie de un formular care poate fi extins la cerere. Acest lucru se poate face utilizand un buton, care va fi adaugat formularului initial în urma utilizarii optiunii ADD OBJECT. Prin utilizarea acestei optiuni, butonul de control este incorporat în definitia subclasei. Prin urmare, el poate fi mostenit. Dupa adaugarea butonului, este necesar ca evenimentului CLICK sa I se asocieze o metoda, pentru ca acesta sa reactioneze.

Evenimente

Evenimentele sunt cele care pun totul în miscare în programarea orientata spre obiecte. Executia unui clic cu mouse-ul este un eveniment. Apasarea unei taste este un eveniment.

1. Recunoasterea evenimentelor

În majoritatea cazurilor numele evenimentelor în Visual FoxPro sunt destul de sugestive. Cu toate acestea, în tabelul urmator sunt prezentate cateva evenimente alaturi de scurte descrieri.

Majoritatea obiectelor utilizează maxim zece evenimente, iar dintre acestea doua sau trei sunt comune tuturor obiectelor. Nu se pot modifica evenimentele pe care un obiect le recunoaste și nici nu se pot adauga altele noi.

2. Asocierea metodelor la evenimente

Pentru a asocia unele actiuni unui eveniment este necesar sa se plaseze o procedura în segmentul de cod DEFINECLASS. Atunci cand se definește procedura pentru un eveniment, trebuie ca numele evenimentului sa fie precedat de numele obiectului, deoarece pot exista în aceeași clasa mai multe obiecte diferite care au același eveniment. Este necesara folosirea obligatorie a referintelor relative (cuvinte cheie, care reprezinta scurtaturi de referinte la obiecte) pentru generalizarea referintelor care vor fi incapsulate în definitia unei clase. Tabelul urmator prezinta cateva cuvinte cheie utilizate pentru a face referire la obiecte și definitiile lor :

Se pot adauga proprietati și metode unui obiect, nu se poate adauga însă un nou eveniment. Nu se pot modifica tipurile de evenimente recunoscute de Visual FoxPro pentru nici un control.

Referențierea obiectelor

Exista mai multe moduri pentru a face referire la obiecte. Se poate folosi un pseudonim deoarece un obiect poate avea mai multe nume care sa faca referire la el. De asemenea, atunci cand un obiect contine mai multe obiecte, se poate face referire la obiectele individuale folosind o ierarhie de nume de obiecte sau se poate asocia un nou pseudonim care sa reprezinte orice portiune a ierarhiei. În continuare sunt mentionate doua noi metode de a face referire la obiecte, prin intermediul masivelor, respectiv prin rezolvarea domeniului.

1. Utilizarea masivelor de obiecte

Dacă se construieste un formular care are un grup de butoane (sau alte controale) inrudite, fiecare obiect se poate defini prîntr-o referinta distincta la obiectul respectiv. În acest caz ar fi nevoie însă de cate o procedura distincta pentru fiecare eveniment al fiecarui obiect. Prin gruparea obiectelor intr-un masiv, se poate folosi o singura procedura pentru fiecare eveniment comun, definind actiunile individuale prin intermediul unei instructiuni CASE. Mașivele de obiecte sunt similare masivelor de orice alt tip de variabile. De exemplu, fiecare membru poate contine un alt tip de obiect. Primul obiect ar putea fi un buton de comanda, urmatorul, un buton radio și asa mai departe. Dacă se redimenșioneaza masivul, Visual FoxPro initializeaza elementele adaugate cu valoarea.F.. Dacă se reduce dimensiunea masivului, obiectele la care fac referire elementele eliminate sunt eliberate.

Pe de alta parte, nu se poate asocia un obiect unui intreg mașiv cu o singura comanda asa cum se asociaza valori altor mașive. De asemenea, nu se poate modifica nici o proprietate comuna tuturor obiectelor în intregul masiv cu o singura instructiune.

2. Metode de referentiere foloșind operatorul de rezolutie a domeniului

Mostenirea poate fi performanta. Atunci cand se creeaza subclase, se mostenesc toate proprietatile și metodele clasei anterioare. Se pot adauga noi proprietati și metode în subclasa. Se pot, de asemenea, rescrie metodele unei clase anterioare.

Dacă se doreste însă și adaugarea de cod unei metode,nu sunt probleme deosebite Dacă este vorba de o linie, doua. Dar Dacă se impune repetarea a zeci de linii, exista riscul ca modificarile sa nu fie efectuate în mod consecvent în toate copiile. O solutie mai buna decat aceasta o reprezinta utilizarea referirii la codul din clasa initiala. Astfel se poate foloși un operator de rezolutie a domeniului (::) pentru a face referire la o metoda a unei clase aflate mai sus în ierarhia de mosteniri. Dacă pentru acest caz se ruleaza programul, caseta de mesaje a clasei initiale va fi urmata de o caseta de mesaje apartinand clasei nou construite.

Crearea claselor personalizate

Se pot crea clase personalizate care nu au elemente vizuale. Ele constau în intregime din proprietati și metode. Aceste clase nu rezerva spatiu pentru evenimente și metode care nu au sens pentru obiecte non-vizuale. De exemplu, nu sunt necesare evenimente pentru mouse, evenimente drag-and-drop, evenimente de activare etc.

Se definește o variabila de memorie într-o procedura utilizata drept metoda pentru un obiect personalizat. Mai mult, variabila este declarata publica. O problema deosebita ce poate sa apara este impoșibilitatea accesarii acestei valori a variabilei din alta parte a aplicatiei, decat aceea în care a fost definita. Motivul pentru care se intampla acest lucru este ca toate variabilele definite și utilizate în definitia unei clase devin incapsulate în ea. Aceasta inseamna ca ele nu exista nicaieri altundeva decat în obiectul respectiv. Dacă se doreste accesarea unei variabile care este definita într-o metoda a unei clase, trebuie fie sa se initializeze variabila și sa I se declare domeniul în exteriorul obiectului, fie sa se defineasca ca fiind o noua proprietate care poate fi accesata foloșind notatia cu punct.

Crearea unei biblioteci de clase

Dacă obiectul creat este un obiect vizual, se poate beneficia de capacitatea oferita de Visual FoxPro de a crea o biblioteca de clase. Ulterior, se poate atasa și foloși aceasta biblioteca comuna în aplicatii.

Pentru a initia o bibliotaca de clase, aceasta trebuie creata :

CREATE CLASSLIB USEFOX

Aceasta instructiune creeaza un fișier fizic cu extenșia VCX pe discul curent sau pe cel prestabilit. se poate furniza un nume și o cale pentru a crea fișierul pe orice disc și în orice director. De asemenea, se poate specifica o extenșie diferita de VCX. Totuși, extenșia prestabilita fiind VCX, Dacă în aceasta instructiune sau oriunde altundeva nu se specifica extenșia, este utilizata biblioteca de clase.

Pentru biblioteca de clase trebuie creata o clasa, care poate fi personalizata prin foloșirea oricarei clase de baza suportate de Visual FoxPro. Se poate face de asemenea referire la o clasa personalizata prin includerea clauzei FROM <NumeBibliotecaDeClase> care indica programului VPF unde sa o caute.

Pentru a utiliza o biblioteca de clase, este necesar ca aceasta sa fie deschisa cu comanda urmatoare :

SET CLASSLIB TO \UȘINGFOX.300\PROGRAMS\USEFOX.VCX

Dacă exista mai multe biblioteci de clase, se adauga cuvantul ADDITIVE la sfarșitul comenzii.

JUSTIFICAREA LUCRĂRII

Aplicația “Smart Box” are drept scop gestionarea unei biblioteci de CD –uri.

Necesitatea tot mai mare de stocare a datelor și a unor suporturi de date de capacitati tot mai mari duce la solutia CD –urilor, care sunt ieftine și performante avand în vedere raportul calitate-pret. Acest lucru a generat o explozie a numarului acestora. Ceea ce impune, în cazul unei firme cu un numar relativ mare de CD- uri, foloșirea unei aplicatii PC. Este de asemenea o solutie comoda și sigură.

Sa consideram un exemplu: Dacă acasa avem la dispozitie 5 CD –uri cu soft, 3 cu muzica comprimata, 5 cu muzica necomprimata, 5 cu jocuri, 20 reviste și 5 prieteni care ar dori sa imprumute cate unul sau doua din aceste CD-uri, ar fi o adevarata povara sa luam un caiet sa scriem de fiecare data numele CD –ului, sa incepem sa cautam unde ar putea fi imprumutat un CD care ne este necesar urgent. Asadar, o aplicatie ca aceasta este binevenita. Cu atat mai mult, într-o firma cu 100 angajati care doresc sa imprumute din biblioteca de probabil 50 sau 100 de CD –uri ar fi imposibil de tinut o evidenta corecta și rapida fara ajutorul calculatorului.

Nucleul lucrarii este baza de date “smartbox.dbc”. Contine tabelele necesare, relațiile permanente, triggerele și procedurile aferente unei baze de date relaționale.

S-au folosit avantajele programarii orientate pe obiecte. Utilizarea claselor da aplicatiei o structura organizata, acceșibila programatorului.

PREZENTAREA BAZEI DE DATE “SMART BOX”

Pentru indeplinirea scopului principal al aplicatiei vom folosi urmatoarele tabele principale :

A) tabela “IMPRUMUTURI” care sa cuprinda, în principiu, urmatoarele date:

numele departamentului care imprumuta

numele angajatului care poarta responsabilitatea pentru CD- ul imprumutat

numele CD- ului

data imprumutarii

B) tabela “ARHIVA” cu evidenta CD-urilor imprumutate și returnate. Se doreste ca în timp sa se observe ce CD- uri au fost mai folosite, cine a imprumutat mai multe CD-uri. În plus nu se doreste ca în tabela de imprumuturi sa apara și cele returnate, pentru o mai usoara utilizare a aplicatiei.

C) tabela “ITEMS” care cuprinde CD- urile, avand în componenta urmatoalere câmpuri:

numele CD-ului

domeniul din care face parte softul de pe el

luna și anul în care au fost scoase pe piata – de exemplu pentru CD-urile anexate diverselor reviste este bine sa știm luna și anul revistelor respective, care pot sa fie diferite de luna și anul în care introducem informația în aplicatia “SmartBox:”.

data curenta

eticheta CD-ului inscriptionata de catre fabrica producatoare pe CD, necesara pentru identificarea fara posibilitate de eroare a unui CD.

Pe langa aceste tabele principale, care cuprind datele necesare în primul rand, luand în considerare normalizarea datelor și dependența functionala, mai sunt necesare urmatoarele tabele:

tabela de departamente de utilizatori

tabela de utlizatori din departamentele de mai sus

tabela cu tipuri de CD-uri. De exemplu film, documentare, muzica, etc.

La crearea tabelelor din baza de date s-a tinut cont de urmatoarele principii:

stocarea informațiilor o singura data reduce riscul aparitiei erorilor;

prevenirea stergerii informațiilor de valoare;

neincluderea datelor calculate sau derivate din alte date ;

stocarea informațiilor în câmpuri de tip și marime optime și cat mai mici din punct de vedere logic.

Structura bazei de date este urmatoarea :

Relațiile de integritate referentiala respecta urmatoarele reguli :

Tabela “DEPARTAMENTE”

Câmpul “id_dpt” are rol de identificator unic pentru fiecare departament. Este deci cheie primara și va fi foloșit pentru integritatea referentiala în relația cu celelalte tabele.

Tabela “UTILIZATORI”

Câmpul “id_ut” este identificator pentru utilizatori.

Câmpul “nume_ut” definește numele utilizatorului și este de tip candidat pentru a nu fi introdus același nume de 2 ori.

Câmpul “id_dpt” apare pentru identificarea departamentului din care face parte utilizatorul respectiv.

Tabela “ IMPRUMUTURI” :

Contine informații directe cu privire la cine, ce și cand a imprumutat.

De remarcat ca sunt foloșite câmpurile de identificare pentru denumirile respective. Foloșim acest mod de lucru deoarece câmpurile de identificare sunt mai scurte, mai rapid de indexat. Pentru numele unui CD, de exemplu vom foloși câmpul nume_item, tip caracter de lungime 30. O cheie primara pe acest câmp este mult mai greoaie pentru aplicatie decat câmpul id_item, tip numeric de lungime 5 cu 0 zecimale. În plus schimarea numelui unui CD este mai șimplu de realizat deoarece identificatorul ramane același.

Tabela “TIPOBIECT”

De remarcat câmpul “capturare” de tip logic care se refera la faptul ca respectivului item ii poate fi capturata structura. De exemplu pentru CD –uri putem face capturarea structurii de directoare, în schimb pentu reviste nu putem face acest lucru.

Tabela “ITEMS”

Contine numele itemurilor din biblioteca : CD –uri, reviste.

Remarcam existanta câmpurilor :

luna, an care reprezinta luna și anul inscrise pe CD, de exemplu pentru CD –urile atasate revistelor CHIP, PC REPORT putem scrie luna și anul de editare.

data_a care reprezinta data de adaugare în baza de date ;

câmpul “label” reprezinta eticheta inscriptionata de fabrica pe CD, pentru poșibilitatea de identificare a sa, fara poșibilitatea unei erori

câmpul “imprumutat” de tip logic pentru informarea rapida Dacă e disponibil pentru a fi imprumutat

Tabela “ITEMS_DET”

Contine detalii cu privire la itemurile din biblioteca. Anume, pentru CD –uri contine ceea ce a fost capturat de pe ele : structura de fișiere sau simple informații editate manual de catre utilizatori.

Mai contine și câmpul “observatii “ pentru notarea de observatii cu privire la detaliile respective.

Tabela “IDKEY”

Aceasta tabela are rol strict functional, și anume acela de a furniza numere de identificare pentru înregistrări. Pentru a putea crea înregistrări noi fara sa tinem cont de ceilalti utilizatori din retea e necesar sa putem lua numere de identificare care sa nu coincida cu cele luate de ceilalti din retea. De exemplu, în tabela “utilizatori” numarul de identificare cel mai mare este 152. Am creat o înregistrare noua. Numarul de identificare maxim devine 153. Dacă nu facem salvarea imediata a înregistrării atunci numarul de identificare maxim din tabela originala ramane tot 152. Dacă cineva din retea creeaza o noua înregistrare în tabela “utilizatori “, nu stie ca eu am o noua înregistrare și poate da numarului de identificare tot valoarea 153. De aceea e necesara o tabela care sa poate fi actualizata imediat și care sa contina numarul de identificare maxim la care s-a ajuns în fiecare tabela.

Vederea “V_ARHIVA”

Din motive functionale s-a creat vederea “v_arhiva”. Este o vedere pentru tabela “arhiva” care s-a creat pentru a putea ordona înregistrările din tabela “arhiva” dupa nume item sau nume utilizator.

Dacă am fi lucrat direct cu tabela “arhiva”, ordonarea s-ar fi putut face dupa id_ut sau id_item. În aceste cazuri ordonarea dupa id_ut nu ar fi fost alfabetica, ci de fapt dupa id_ut.

Privire de detaliu asupra bazei de date

Pentru crearea identificatorilor din tabele se foloseste procedura “getid()” din “util.prg”.

S-au stabilit valori implicite acolo unde e necesar. De exemplu pentru data imprumutarii unui CD se da valoare implicita data și ora din momentul respectiv.

Pentru toate tabelele, cu exceptia items_det și arhiva s-a creat un câmp de tip cheie primara care este utilizat în relațiile de integritate referentiala.

S-a urmarit protejarea datelor în cazul stergerii sau modificarii lor. De exemplu, nu se poate sterge un CD implicat intr-un imprumut. De asemenea, nu se poate adauga la imprumuturi un CD care nu exista în tabela “items”. Toate aceste conditii sunt indeplinite cu ajutorul relațiilor de integritate referentiala definite în baza de date. Aceste relații au fost create cu ajutorul “Referential Integrity Builder”. Regulile stabilite pentru toate relațiile sunt de tipul:

CASCADA – pentru actualizare – la actualizarea înregistrării parinte se actualizeaza și înregistrările corespunzatoare din tabela fiu.

RESTRICT – pentru inserare – nu e permisa inserarea unei înregistrări în tabela fiu fara ca aceasta sa existe în tabela parinte

RESTRICT – pentru stergere – nu e permisa stergerea unei înregistrări în tabela parinte Dacă aceasta exista în tabela fiu.

Aplicatia mai cuprinde urmatoarele :

Programe

main.prg – programul principal în care se initializeaza aplicatia. Se executa configurari initiale și se creeaza obiectul de tip “aplicatie” definit în cele ce urmeaza la capitolul “Clase”

util.prg – contine functii și proceduri utilizate în cadrul aplicatiei

PROCEDURE get_id – extrage un nou identificator pentru tabele

FUNCTION encom(lobjname) – stabileste starea de activare a unui obiect din bara de instrumente

FUNCTION encomnew() – stabileste starea de activare a butonului “new” din bara de instrumente

FUNCTION encomdelete()- stabileste starea de activare a butonului “delete” din bara de instrumente

FUNCTION IsTag (tcTagName, tcAlias)- determina existenta unui tag (index) intr-un alias

FUNCTION FormIsObject() – determnina Dacă un formular exista și este de tip obiect

Function doerror(nerror,cmethod,nline) – functia de tratare a erorilor (în afara formularelor care trateaza intern erorile

FUNCTION OnShutdown() – functia care se executa Dacă se da shutdown în timpul rularii aplicatiei

FUNCTION fadir(ldirector) – functia care captureaza structura directoarelor de pe CD

Clase

baza.vcx – librarie de clase care cuprinde clase care se vor utiliza pentru crearea diverselor controale în formulare și nu numai.

plus.vcx

 În cele ce urmeaza prezentam pe scurt codul celor 2 clase.

BAZA.VCX

**************************************************

*– Class: dbaseform (c:\lucru\proiecto\clase\baza.vcx)

De remarcat existenta urmatoarelor metode

*– Muta cursorul la înregistrarea urmatoare

PROCEDURE next

*– Muta cursorul la prima înregistrare

PROCEDURE first

*– Muta cursorul la ultima înregistrare

PROCEDURE last

*– Muta cursorul la înregistrarea anterioara

PROCEDURE prior

*– Salveaza modificarile în aliasul curent

PROCEDURE save

*– Sterge înregistrarea curenta

PROCEDURE delete

*–Anuleaza modificarile facute de la ultima salvare. Totodata anuleaza o înregistrare noua Dacă nu a fost salvata.

PROCEDURE restore

*– Apelarea metodei Refresh

PROCEDURE refreshform

*– Schimba modul “wait” pentru cursor în controalele de pe ecran.

PROCEDURE waitmode

*–Adauga numele formei la menul “Window” al aplicatiei..

PROCEDURE addtomenu

*– Sterge numele formei din menu

PROCEDURE removefrommenu

*– Afiseaza intrebare de salvare a modificarilor.

PROCEDURE asktosave

*– Pregateste pentru o noua înregistrare

PROCEDURE new

*– Actiunea de imprimare a unui raport

PROCEDURE imprima

*– Datele schimbate ?

PROCEDURE datachanged

*– Salveaza valoarea controlului curent

PROCEDURE writebuffer

PROCEDURE activarecimp

**************************************************

*– Class: dpageform (c:\lucru\proiecto\clase\baza.vcx)

PROCEDURE new

**************************************************

*– Class: dcheckbox (c:\lucru\proiecto\clase\baza.vcx)

**************************************************

*– Class: dcombobox (c:\lucru\proiecto\clase\baza.vcx)

**************************************************

*– Class: dcommand (c:\lucru\proiecto\clase\baza.vcx)

**************************************************

*– Class: deditbox (c:\lucru\proiecto\clase\baza.vcx)

**************************************************

*– Class: dgrid (c:\lucru\proiecto\clase\baza.vcx)

DEFINE CLASS dgrid AS grid

*– Nr. de cicluri la apasarea repetata a headerului.

PROTECTED cyclecount

cyclecount = 1

*– Coloana curenta.

PROTECTED crtcolumn

crtcolumn = "''"

Name = "dgrid"

*– Stabileste ordinea de afisare (index) parametrii: tag, numarcoloana

PROCEDURE setorder

lparameters tagname,col_name

this.setall("forecolor",RGB(0,0,0),"header")

this.cyclecount=this.cyclecount+1

if this.crtcolumn#col_name

this.cyclecount=2

endif

if this.cyclecount=4

this.cyclecount=1

endif

lname=EVAL('this.'+col_name)

do case

case this.cyclecount=1

set order to

lname.header1.forecolor=RGB(0,0,0)

case this.cyclecount=2

set order to tag &tagname ascending

lname.header1.forecolor=RGB(255,0,0)

case this.cyclecount=3

set order to tag &tagname descending

lname.header1.forecolor=RGB(0,0,255)

endcase

this.crtcolumn=col_name

thisform.refresh()

ENDPROC

ENDDEFINE

*– EndDefine: dgrid

**************************************************

*– Class: dlabel (c:\lucru\proiecto\clase\baza.vcx)

**************************************************

*– Class: dlistbox (c:\lucru\proiecto\clase\baza.vcx)

**************************************************

*– Class: doptiongroup (c:\lucru\proiecto\clase\baza.vcx)

**************************************************

*– Class: dtextbox (c:\lucru\proiecto\clase\baza.vcx)

**************************************************

*– Class: ingrid (c:\lucru\proiecto\clase\baza.vcx)

**************************************************

*– Class: standardform (c:\lucru\proiecto\clase\baza.vcx)

DEFINE CLASS standardform AS form

*– Toggles the wait cursor on and off for all controls on the screen.

PROCEDURE waitmode

*– Adds the caption of the form to the Window menu.

PROCEDURE addtomenu

*– Removes the caption of the form from the Window menu.

PROCEDURE removefrommenu

**************************************************

PLUS.VCX

**************************************************

*– Class: aplicatie (c:\lucru\proiecto\clase\plus.vcx)

**************************************************

*– Class: apptoolbar (c:\lucru\proiecto\clase\plus.vcx)

*– ParentClass: toolbar

DEFINE CLASS apptoolbar AS toolbar

**************************************************

*– Class: apptoolbarbutton (c:\lucru\proiecto\clase\plus.vcx)

**************************************************

*– Class: apptoolbarclock (c:\lucru\proiecto\clase\plus.vcx)

*– ParentClass: timer

DEFINE CLASS apptoolbarclock AS timer

**************************************************

*– Class: dformretval (c:\lucru\proiecto\clase\plus.vcx)

*– ParentClass: form

DEFINE CLASS dformretval AS form

**************************************************

*– Class: about (c:\lucru\proiecto\clase\plus.vcx)

*– ParentClass: dformretval (c:\lucru\proiecto\clase\plus.vcx)

DEFINE CLASS about AS dformretval

**************************************************

*– Class: dtoolbar (c:\lucru\proiecto\clase\plus.vcx)

*– ParentClass: toolbar

*– Saves the poșition of the toolbar to the INI file.

PROTECTED PROCEDURE savewindowpos

*– Restores the window's poșition from the INI file.

PROTECTED PROCEDURE restorewindowpos

PROCEDURE cmdprint.Click

PROCEDURE cmdfirst.Click

PROCEDURE cmdprior.Click

PROCEDURE cmdnext.Click

PROCEDURE cmdlast.Click

PROCEDURE cmdnew.Click

PROCEDURE cmdsave.Click

PROCEDURE cmdrestore.Click

PROCEDURE cmddelete.Click

PROCEDURE cmdclose.Click

**************************************************

*– Class: dtoolbarbutton (c:\lucru\proiecto\clase\plus.vcx)

**************************************************

*– Class: environment (c:\lucru\proiecto\clase\plus.vcx)

*– Setari specifice seșiunii private de date

PROCEDURE setspecial

Formulare

Formularele au fost create pe baza a una din urmatoarele 2 categorii de clase:

pe baza clasei de baza “form”

pe baza uneia din clasele de tip “form” din librariile “baza.vcx”,”plus.vcx”.

Acestea sunt :

“standardform” – tip standard

“dbaseform” – tip de baza pentru formulare cu una sau 2 tabele

“dpageform” – formular pentru tabele cu o singura tabela

“dformretval” – formular care returneaza o valoare

Majoritatea formularelor contin tabele. Au fost foloșite zone tampon pentru înregistrări pe o înregistrare pentru tabela parinte sau pe toate înregistrările pentru tabela fiu. Prin urmare, aplicatia este multi-user.

Formularele care tin evidenta cuprind 2 subpagini: în prima se face introducerea / modificarea unei înregistrări iar în a doua se vizualizeaza lista cu toate înregistrările din care se alege cea dorita pentru modificare în subpagina 1.

imprumuturi – tabela principala cu imprumuturi

S-au folosit zone tampon de înregistrări astfel:

pe o înregistrare pentru tabelele “utilizatori”, “arhiva”.

pe toate înregistrările pentru tabela “imprumuturi”.

Subpagina de actualizare cuprinde o lista cu itemurile din care putem alege unul pentru stabilirea unui imprumut. În dreapta sus avem un control de tip « combobox » cu utilizatorii, din care alegem pe cel care efectueaza imprumutul. În dreapta jos avem un control de tip « grid » în cu detaliile privitoare la imprumuturile efectuate de catre un utilizator. Butonul de deasupra gridului realizeaza functia de returnare a unui imprumut. El scoate înregistrarea din imprumuturi și o introduce ca înregistrare noua în tabela « arhiva ».

Adaugarea unui imprumut nou pentru utilizatorul curent se poate face în mai multe moduri :

prin folosirea butonului « New » din bara de instrumente ;

prin tragerea unui item din lista peste tabela de imprumuturi. Apare un meniu care ne intreaba dacă dorim sa modificam înregistrarea curenta sau sa adaugam o înregistrare noua;

prin click dreapta cu mouse-ul peste gridul cu imprumuturi apare un alt meniu din care putem alege sa introducem o înregistrare noua

Butonul de stergere din bara de instrumente sterge definitiv o înregistrare, fara sa o mai introduca în arhiva. A fost creat acest buton pentru cazul în care se introduce un imprumut, dar se face returnarea tot atunci din diverse motive. Ar fi neconcludenta o introducere în arhiva.

arhiva – arhivarea imprumuturilor returnate

Prin stergerea cu ajutorului butonului din dreapta jos se pot sterge definitiv înregistrările din arhiva.

items – evidenta CD- urilor din biblioteca

S-au foloșit zone tampon de înregistrări astfel:

pe o înregistrare pentru tabelele “items”.

pe toate înregistrările pentru tabela “items_det”.

În subpagina de introducere/modificare avem, pe langa câmpurile necesare, un tabel cu înregistrările din tabela “items_det” care cuprinde detaliile cu privire la un item : structura de fișiere a unui CD, articole dîntr-o revista s.a..

Pentru capturarea structurii unui CD foloșim butonul “Capturare structura” în care, cu ajutorul unei functii autoapelante, foloșind functia “ADIR” aflam structura de directoare. Nu exista în Visual FoxPro o functie care prin șimpla apelare sa faca acest lucru.

Butoanele “+” și “-“ adauga, respectiv sterge din tabela de detalii.

Pentru facilitarea stergerii tuturor înregistrării am realizat formularul “mesaj” care foloseste la afisarea mesajului prin care se stabileste optiunea pentru stergerea uneia sau a mai multor înregistrări în items. Anticipam faptul ca tabela items_det va avea foarte multe înregistrări. Sa ne gandim la un CD, pe care putem avea sute sau mii de fișiere. De aceea, pentru o operare usoara și rapida, avem poșibilitatea stergerii tuturor înregistrărilor din detalii corespunzatoare itemului curent.

Totodata, pentru stabilirea parametrilor la capturarea structurii CD –urilor am realizat formularul “mesaj_capt” în care se alege, dupa preferinta, dacă se captureaza fișiere, directoare și dacă da, pana la ce subramura.

4. departamente – evidenta departamentelor cu angajati

S-au folosit zone tampon de înregistrări pe o înregistrare pentru tabela “departamente”.

utilizatori – evidenta utilizatorilor care imprumuta

S-a foloșit zona tampon de înregistrări pe o înregistrare pentru tabela “utilizatori”.

Pentru evidenta utilizatorilor, avem controlul de tip “combobox” care are “RowSource=departamente.nume_dpt” pentru a putea alege din lista de departamente pe cel caruia apartine utilizatorul respectiv.

Pentru adresa, fiind un câmp de tip “memo” am foloșit un control de tip “editbox”.

obiecte – evidenta tipuri de CD –uri

S-a folosit zona tampon de înregistrări pe o înregistrare pentru tabela “tipobiect”.

De remarcat căsuța de validare « suporta captura » care, printr-un câmp de tip logic stabileste Dacă obiectul respectiv suporta sau nu captura. Adica, Dacă, de exemplu, avem un CD, casuta va fi bifata, Dacă avem o revista nu va fi bifata, deoarece unei reviste nu-I putem captura structura de directoare. Aceasta proprietate va determina Dacă butonul « Capturare structura » din formularul « ITEMS » va fi activ sau nu.

status – afiseaza o forma de stare la intretinerea bazelor

intretin – formularul de la intretinerea bazelor.

E necesar ca, periodic, sa se dea « Intretinere baze » în primul rand pentru refacerea indecșilor. Dacă un index este stricat, apar erori. Cu atat mai mult atunci cand, de exemplu, o lista nu e corect ordonata, dar nu numai atunci, e necesara o reindexare. La indexare, chiar Dacă un tabel sau baza de date sunt stricate, li se va reface structura deoarece programul de Intretinere Baze preia informațiile cu privire la structura bazei de date din tabela « data\dbcinfo.dbf ». De aceea trebuie ca aceasta tabela sa nu fie deteriorata sau stearsa.

Meniuri

main – meniul principal al aplicatiei

drag – meniul care apare la modificare/adaugarea unei înregistrări în imprumuturi

sh_impr – meniu pentru lucrul cu înregistrările în imprumuturi

Aplicatia foloseste 2 tipuri de bare de instrumente:

bara pentru controlul înregistrărilor la modificarea în formulare : pe baza clasei “dtoolbar”. Se poate naviga inainte și inapoi pe înregistrări, se poate adauga înregistrare noua, se poate sterge o înregistrare, se salveaza sau anuleaza modificarile.

bara pentru accesarea rapida a formularului “imprumuturi” – pe baza clasei “apptoolbar”

Ambele clase se afla în libraria “plus.vcx”.

Fișiere text

smartbox.h – contine constantele de preprocesare foloșite în aplicatie

Pentru facilitarea scrierii codului s-au foloșit constantele de preprocesare. Acestea, în general, incearca sa semnifice cat mai mult, functionalitatea constantelor respective.

Alte fișiere

Fișiere grafice de tip ‘.bmp’, ‘.ico’.

Explicarea functionarii aplicatiei

Programul principal la pornirea aplicatiei este main.prg. Acesta incepe cu directiva de preprocesare #INCLUDE « smartbox.h » care include constantele de preprocesare folosite în aplicatie.

Apoi este declarata procedura în caz de eroare, se fac configurari de mediu initiale și se creaza obiectul de tip “aplicatie” care este stocat în libraria de clase “plus.vcx”.

#INCLUDE "smartbox.h"

PUBLIC oApp

oApp = CREATEOBJECT("Aplicatie")

La crearea obiectului « aplicatie » se executa procedura « Init » în care se stabilesc parametrii de mediu prin crearea obiectului « oenvironment » din clasa « environment ». Se deschide baza de date aferenta aplicatiei și se inchid barele cu instrumente, Dacă acestea sunt.

Aplicatie.Init()

this.AddObject("oEnvironment", "Environment")

this.oEnvironment.Set()

OPEN DATABASE (this.BazaDeDate)

this.ReleaseToolBars()

Apoi se executa metoda « Do » a obiectului « aplicatie » care fusese apelata inca din main.prg. Se stabilesc proprietatile ecranului, anume: icon, culoarea desktopului, culoarea textului. Se adauga la ecran un obiect de tip imagine care va contine pictura « smartbox.bmp », adica sigla aplicatiei.

Aplicatie.Do()

_screen.lockscreen=.t.

_screen.caption = this.cMainWindCaption

_screen.icon = this.icon

_screen.backcolor=rgb(64,64,64)

_screen.forecolor=rgb(0,255,0)

_screen.addobject('poza','image')

_screen.poza.picture='SmartBox.bmp'

_screen.poza.backstyle=0

this.reșize()

DO (this.mainmenu)

_screen.lockscreen=.f.

_screen.vișible=.t.

this.gentoolbar=CREATEOBJECT('apptoolbar')

this.genToolBar.Show()

this.genToolBar.Refresh()

_screen.addobject('demon','apptoolbarclock',oapp.gentoolbar)

oapp.oenvironment.setspecial()

READ EVENTS

Tot aici se lanseaza și meniul principal al aplicatiei. Din acest moment se poate incepe lucrul efectiv în aplicatie.

Meniul principal contine submeniurile :

File cu :

Ieșire

Intretinere baze – face reindexarea tabelelor.

Adauga ; Salveaza; Renunta; Sterge – activate în cadrul formularelor. Folosesc la controlul înregistrărilor. Dubleaza, practic, bara de intrumente “dtoolbar”.

Adauga pozitie; Sterge pozitie – adauga și respectiv sterge o înregistrare din tabela din formularul curent.

Print Setup – face configurarea imprimantei pentru rapoarte.

Ieșire program – inchide aplicatia

Nomenclator – contine formularele de introducere a nomenclatoarelor de denumiri. Contine

Obiecte

Departamente

Utilizatori

Items

Operatii – contine formularele principale ale aplicatiei

Imprumuturi

Arhiva

Rapoarte

Cautare în detalii – formularul de cautare a unei expreșii sau a unui fișier în detaliile cu privire la items (CD -uri)

Meniul mai cuprinde 4 submeniuri care nu tin direct de aplicatie:

Navigatie – pentru navigarea pe înregistrări în tabele

Utilities – pentru depanarea aplicatiei în caz de erori

Window – cuprinde ferestrele active la un moment dat

Help – contine ajutor referitor la aplicatie

Discutie asupra unor probleme aparute

I) Procedura FADIR()

Nu avem o functie în Visual FOX pentru capturarea intregii structuri a unui director. De aceea apelam la functia ADIR(). Aceasta functie are urmatoarea șintaxa :

LnReturnat= ADIR(Numeșir [, StructuraFișiere [, Atribut]])

Unde

Numeșir – reprezinta numele șirului care se creeaza și contine indormatiile despre fișiere / directoare. Are 4 coloane care reprezinta numele, marimea, data ultimei modificari, ora ultimei modificari și atributul fișierului.

StructuraFișiere – reprezinta directorul din care se culeg informațiile și, în cazul fișierelor, tipul de fișiere cautat. De exemplu, pentru fișiere de tip “.dbf” din directorul curent avem “*.dbf”.

Atribut – poate lua valorile D, H, S sau V. În functie de acesta functia poate returna una din urmatoarele:

Atribut= D – returneaza subdirectoarele și fiserele ce respecta criteriul din parametrul 2

S – returneaza fișierele șistem ce respecta criteriul din parametrul 2

H – returneaza fișierele ascunse ce respecta criteriul din parametrul 2

V – returneaza volumul drive-ului curent

Codul procedurii este urmatorul :

* parametrii initiali

*ldirector – directorul de capturat

*ldir -.T./.F. Dacă vrem/nu vrem capturarea numelor directoarelor

*ldirnivel – nivelul (subramura) pana la care se face capturare (în jos)

*lfis -.T./.F. Dacă vrem/nu vrem capturarea numelor fișierelor

*lAlias – aliasul bazei în care se adauga numele de fișiere și directoare

*lCâmp – numele câmpului în care se introduc numele de fișiere și directoare

LPARAMETERS ldirector,ldir,ldirnivel,lfis,lAlias,lCâmp

* variabile locale foloșite

LOCAL lOlddefa, lnrfis, lnrdir, afișiere[1,1], adirector[1,1], lnewdir, i, ldirector, lSalvat, ltable

* Dacă numarul de parametri primiti de procedura e diferit de 6 dam mesaj și oprim procedura

if PCOUNT() # 6

=messagebox('Nr. de parametri incorect')

return

endif

* Dacă nu exista baza în care adaugam fișierele dam mesaj și oprim procedura

if !USED(lAlias)

=messagebox('Baza în care se adauga nu exista')

return

endif

* salvam directorul implicit

lSalvat=SYS(5)+SYS(2003)

* stabilim cam director implicit directorul pasat procedurii ca parametru

SET DEFA TO ADDBS(ldirector)

* capturam fișierele din director

lnrfis=ADIR(afișiere,ADDBS(ldirector)+'*.*')

* Dacă numarul de fișiere este nenul și parametrul care determina Dacă se captureaza fișiere este.T. atunci, pentru toate liniile din șir se insereaza în lAlias, câmpul lCâmp, numele fișierelor

if lnrfis>0.AND. lfis

for i=1 to ALEN(afișiere,1))

INSERT INTO (lAlias) (&lCâmp) VALUES ( LOWER(afișiere(i,1)) )

endfor

endif

* capturam subdirectoarele din director

lnrdir=ADIR(adirector,"",'D')

* Dacă parametrul care determina Dacă se captureaza directoare este.T. atunci, pentru toate liniile din șir se insereaza în lAlias, câmpul lCâmp, numele directoarelor, fara înregistrările”.” și “..” care apar la capturarea directoarelor

if ldir

for i=1 to ALEN(adirector,1))

if adirector(i,1)#'.'.AND. adirector(i,1)#'..'

INSERT INTO (lAlias) (&lCâmp) VALUES (JUSTFNAME(adirector(i,1)))

endif

endfor

endif

* pentru directoarele din șir se reapeleaza functia ADIR(). Dacă ldirnivel este natural pozitiv se paseaza ldirnivel decrementat cu o unitate. Altfel se paseaza la aceeași marime.

for i=1 to lnrdir

if adirector(i,1)='.'.OR. adirector(i,1)='..'

LOOP

endif

if ldirnivel#-1

if ldirnivel<=1

exit

endif

=fadir(ADDBS(ldirector)+adirector(i,1),ldir,ldirnivel-1,lfis,lAlias,lCâmp)

else

=fadir(ADDBS(ldirector)+adirector(i,1),ldir,ldirnivel,lfis,lAlias,lCâmp)

endif

endfor

* se restabileste directorul implicit la cel initial

set defa to ADDBS(lSalvat)

*Dacă ldirnivel este diferit de –1 se incrementeaza cu 1 pentru a reveni la valoarea initiala

if ldirnivel#-1

ldirnivel=ldirnivel+1

endif

Aceasta este forma finala a codului.

O forma simplificata a codului ar putea fi :

definire parametri și variabile locale

salvarea directorului implicit într-o variabila

apelare functie ADIR() pentru gasire fișiere

apelare functie ADIR() pentru gasire directoare

scanare a șirului de directoare gasit și reapelarea în acest moment a aceleiași functii FADIR()

restabilirea directorului implicit la cel salvat initial

Se observa ca parametrul ldirnivel se decrementeaza pana ajunge la nivelul 0 cand procedura se incheie. Dacă are valoarea initiala –1 atunci nu se mai ia în calcul și se captureaza intreaga structura.

I) Cautare în detalii

Avand în vedere ca dorim o cautare și în interiorul câmpului de detalii, dispunem de functia LOCATE, care, însă, nu este o solutie buna avand în vedere numarul relațiv mare de înregistrări și marimea câmpului de detalii. De aceea apelam la functia SQL – SELECT care este un puternic motor de cautare și ofera și o bara de progres cu o foarte buna aproximare a timpului de cautare.

Pentru o situatie relevanta vom conșidera tabela “items_det” cu 50414 înregistrări. Dacă folosim functia APPEND pentru a adauga alte 50414 înregistrări e nevoie de 46 secunde. În schimb, folosind functia SELECT … UNION e nevoie de doar 28 secunde.

Acest tabel se poate transpune în urmatorul grafic :

Asadar e necesar cu 64 % mai mult în cazul functiei APPEND.

Am folosit operatorul “%” pentru a cauta în interiorul câmpului. De exemplu, pentru a cauta expreșia “e.r”, folosim astfel:

SELECT detaliu FROM itemd_det WHERE detaliu LIKE “%e.r%”.

Pentru inlocuirea unui singur caracter am foloșit operatorul “?”. De exemplu, pentru a cauta expresia “e.r” incepand cu al doilea caracter, foloșim astfel:

SELECT detaliu FROM items_det WHERE detaliu LIKE “?e.r%”.

Pentru cautarea expresiilor de tip fișier, am foloșit tot operatorul “%”, care de fapt ia locul operatorului “*” în lucrul cu fișiere.

local llcase, lcVariabila, line1, line2, line3, ltable, cmdline, lTablename, i, nrcâmp, cdetaliu, loldtalk

thisform.enabled=.f.

ltable=left('a'+sys(3),8)

cdetaliu=''

llcase=thisform.casesens.value

lcVariabila=allt(thisform.dtextbox1.value)

lcVariabila=iif(llcase,lcVariabila,lower(lcVariabila))

do case

case thisform.combo1.value=1 &&detalii

loldtalk=SET("TALK")

set talk on

set talk wind

select items_det.detaliu, items_det.id_item, imprumuturi.id_ut;

FROM items_det LEFT OUTER JOIN imprumuturi;

ON Items_det.id_item = Imprumuturi.id_item;

INTO CURSOR c0

set talk off

line1='select c0.detaliu, c0.id_item, c0.id_ut, utilizatori.nume_ut'+;

' FROM c0 LEFT OUTER JOIN imprumuturi'+;

' ON c0.id_item = Imprumuturi.id_item'

thisform.dgrid1.column1.header1.caption='Detaliu'

cdetaliu='detaliu'

endcase

do case

case thisform.option.value=1

line2= ' where '+iif(llcase,cdetaliu,'lower('+cdetaliu+')')+' like "%'+lcVariabila+'%"'

case thisform.option.value=2

line2= ' where '+iif(llcase,cdetaliu,'lower('+cdetaliu+')')+' like "'+lcVariabila+'%"'

case thisform.option.value=3

line2= ' where '+iif(llcase,cdetaliu,'lower('+cdetaliu+')')+' like "%'+lcVariabila+'"'

case thisform.option.value=4

lcVariabila=STRTRAN(lcVariabila,"?","_")

lcVariabila=STRTRAN(lcVariabila,"*","%")

line2= ' where '+iif(llcase,cdetaliu,'lower('+cdetaliu+')')+' like "'+lcVariabila+'"'

endcase

line3=' INTO CURSOR c1'

CmdLine=line1+line2+line3

set talk on

set talk wind

&cmdline

SELECT c1.*, items.nume_item;

FROM c1 LEFT JOIN items ON c1.id_item=items.id_item;

INTO TABLE (ltable)

set talk off

nrcâmp=afields(câmpuri)

for i=1 to nrcâmp

if INLIST(TYPE(câmpuri(i,1)),"C","M")

cmd='repl '+câmpuri(i,1)+' with "" all for ISNULL('+câmpuri(i,1)+')'

&cmd

endif

endfor

ltablename=DBF()

use

select c_gașite

lOldsafe=SET("SAFE")

set safe off

if thisform.adauginloc.value=1

zap

endif

set safe &lOldsafe

appe from (ltable)

if FILE(ltablename)

delete file (ltablename)

endif

set talk &loldtalk

thisform.enabled=.t.

wait window 'Ready ' nowait

thisform.dgrid1.refresh()

BIBLIOGRAFIE

Microsoft Press, Microsoft Visual FoxPro 6.0 – ghidul programatorului,

Editura TEORA, București, 2000

M. Bazian, J. Booth, J. Long, V. Miller, C. Silver, R. A. Byers, Totul despre

Visual FoxPro 6, Editura TEORA, București, 2001

Michael D. Antonovich, Utilizare Visual FoxPro 3 – editura TEORA

Kevin Kline, SQL în a Nutshell: a Desktop Quick Reference

Menachem Bazian, Special Edition Using Visual FoxPro 6

Savannah Brentnall, Ken Levy, Object Orientation în Visual FoxPro

Similar Posts