Data Access Objects
Data Access Objects (DAO) furnizeazã un set bogat de obiecte, colectii, proprietãti si metode care ne permit un acces în timpul rulãrii aplicatiei la Microsoft Jet, ODBC si servicii de baze de date. Multi utilizatori de Access vãd Microsoft Jet-ul si DAO-ul ca fãcând parte exclusiv din Microsoft Access. În realitate DAO este doar o componentã care împreunã cu alte componente, formeazã o aplicatie Access. Dar DAO este mult mai mult decât o parte a Microsoft Access; este o componentã de acces si management de date disponibilã din orice aplicatie care suportã Automation. Dacã dorim un control prin program asupra datelor dintr-o bazã de date din Microsoft Access, Word, Microsoft Excel, Visual Basic sau din alte aplicatii, atunci acest acces îl obtinem folosind DAO.
Rezumând cele spuse anterior, DAO poate fi caracterizat ca fiind o componentã “independentã de aplicatie” care furnizeazã o interfatã prin program, în timpul rulãrii aplicatiei, cu Microsoft Jet-ul sau servicii de baze de date ODBC.
Implementarea DAO
DAO este implementat sub forma unei ierarhie de colectii si obiecte. Toate tabele, câmpurile, indecsii, query-urile, si asa mai departe, sunt reprezentate ca obiecte organizate în colectii. Fiecare obiect are un set de proprietãti care îi definesc caracteristicile, si unul sau mai multe metode pe care le putem folosi pentru a executa diferite operatii cu obiectele. În continuare dorim sã prezentãm fiecare colectie în parte, precum si obiectele pe care le contin.
DBEngine
Obiectul DBEngine reprezintã motorul de baze de date Microsoft
Jet. Acest obiect contine si controleazã celelalte obiecte din ierarhia
DAO; el nu are asociatã nici o colectie.
Notã: La versiunile anterioare de 3.0, Microsoft Jet era limitat la 10
instante pe sistem, adicã se puteau executa simultan pânã
la 10 aplicatii folosind Jet. Începând cu versiunea 3.0, se pot
rula atâtea procese (executia de engine-uri, alte aplicatii, si asa mai
departe) cât ne permit resursele sistemului. În plus, în cadrul
fiecãrui proces putem avea pânã la 64 de instante ale engine-ului.
De exemplu, noi putem crea 64 de obiecte DBEngine în cadrul unei aplicatii.
Errors
Si folosind DAO pot apare erori. Însã acestea, în caz cã apar sunt stocate automat în colectia Errors, sub forma unor obiecte. Putem folosi aceste informatii pentru a determina ce a cauzat eroarea si pentru a afisa mesaje de eroare pentru utilizatorii aplicatiei. Este important de retinut cã la fiecare eroare DAO, colectia Errors este resetatã, si noul obiect Error este plasatã în colectia Errors. La un moment dat pot exista mai multe obiecte Error în colectie, în cazul în care o singurã operatie a provocat mai multe erori. Operatiile DAO care nu genereazã eroare, nu au nici un efect asupra colectiei Errorrs.
Workspace-uri
Un obiect Workspace existã pentru fiecare sesiune activã Jet. O sesiune descrie o secventã de operatii efectuate de engine. O sesiune începe atunci când un utilizator intrã ca utilizator în sistem (log-in) si se terminã când utilizatorul pãrãseste sistemul (logout). Workspace-ul a fost creat astfel încât sã permitã crearea unui “spatiu” utilizator/parolã si a unui “spatiu” de tranzactii, în cadrul cãrora un anumit utilizator operazã. Colectia Workspaces contine toate obiectele Workspace definite de Microsoft Jet-ul activ. Abilitatea de a crea workspace-uri multiple prin program este importantã, deoarece astfel ne putem loga la Microsoft Jet ca un alt utilizator. De exemplu, la începerea sesiunii m-am logat ca fiind utilizatorul “Paul”, iar din program sã mã logez din nou, ca fiind un alt utilizator: “Popescu”, de exemplu. De asemenea, aceastã posibilitate de a crea mai multe workspace-uri este importantã si prin prisma faptului cã, fiecare Workspace îsi mentine tranzactiile independent de alte workspace-uri, astfel utilizarea mai multor workspace-uri putând fi utilã atunci când avem de administrat multiple seturi de tranzactii independente. Dar despre tranzactii, vom vorbi ceva mai încolo.
Atunci când pornim Microsoft Jet-ul, ceea ce se întâmplã depinde dacã avem sau nu avem setatã securitatea. Dacã nu avem setatã securitate, atunci Microsoft Jet-ul creazã automat un Workspace implicit, DBEngine.Workspaces(0). Valorile proprietãtilor Name si UserName ale Workspace-ului implicit sunt “#Default Workspace” respectiv “Admin”. Dacã dorim sã folosim securitatea, atunci trebuie sã setãm proprietãtite SystemDB, DefaultUserName si DefaultPassword. Atunci când folosim metoda OpenDatabase fãrã sã specificãm un obiect Workspace, atunci obiectul DBEngine.Workspaces este creat implicit.
Users
Microsoft Jet furnizeazã serviciu de securitate cu care ne putem proteja obiectele din baza de date. Modelul de securitate se bazeazã pe utilizatori si grupuri definite într-o bazã de date workgroup. Colectia Users contine toate obiectele User#Default Workspace#” and “Admin pentru un workspace. Un obiect User defineste un cont pentru utilizator; de asemenea fiecare obiect User are o colectie Groups, care contine un obiect Group reprezentând fiecare grup de care apartine utilizatorul.
Groups
Ca si colectia Users, colectia Groups este folositã de Microsoft Jet în modelul de securitate pentru a controla accesul la obiecte. Colectia Groups contine toate obiectele Group. Un obiect Group defineste un grup de utilizatori în obiectul Workspace existent. Fiecare obiect Group are de asemenea o colectie Users care contine un obiect User pentru fiecare din utilizatorii în parte din grup.
Databases
În DAO, un obiect Database reprezintã o bazã de date deschisã. Aceasta
poate fi o bazã de date nativã Microsoft Jet sau o bazã
de date externã. Putem avea mai multe baze de date deschise în
acelasi timp, chiar baze de date de diferite tipuri. Colectia Databases contine toate obiectele Database pentru un workspace. În versiunea Microsoft Access 2.0 si în
versiunile anterioare, un numãr de baze de date sunt deschise automat
atunci când deschidem baza de date cu interfata Microsoft Access-ului.
Acestea includ o serie de wizard-uri si biblioteci cu utilitare pe care Access-ul
le foloseste pentru a-si realiza propriile functii. Atunci când deschidem
o bazã de date folosind interfata utilizator, adicã selectând
optiunea Open Database din
meniul File, Access-ul asigneazã
aceastã bazã de date la prima pozitie din colectia Databases, Databases(0). Celelalte baze
de date pe care Access-ul le deschide sunt folosite intern de Access si nu fac
parte din colectia Database.
În Microsoft Access pentru Windows 95, bazele de date de tip bibliotecã
sunt identificate prin referinte VBA, dar nu sunt încãrcate pânã
nu sunt folosite prima datã.
Microsoft Access atribuie de asemenea
obiectul implicit Workspace,
Workspaces(0), utilizatorului care s-a logat.
TableDefs
Obiectul TableDef reprezintã o tabelã care este salvatã în bazã de date. Acesta include tabele din baza de date curentã, precum si pe cele legate(cunoscute si sub numele de tabele atasate în versiunile anterioare de Microsoft Jet). Este important de retinut cã obiectele TableDef nu reprezintã date stocate in tabelã-ele reprezintã structura unei tabele. Colectia TableDefs contine toate obiectele TableDef pentru o bazã de date.
QueryDefs
Obiectul QueryDef reprezintã un query salvat în baza de date si mentine informatii despre proprietãtile query-urilor, incluzând reprezentarea SQL. Colectia QueryDefs contine toate obiectele QueryDefs pentru o bazã de date.
Fields
Obiectele Field definesc un anumit câmp (sau coloanã). Obiectele TableDef, QueryDef, Index, Relation si Recordset contin colectii Fields.
Parameters
Cu query-urile Microsoft Jet-ului, putem defini parametri formali. Acesti parametri reprezintã valori necunoscute care trebuie sã fie furnizate de utilizatorul care ruleazã query-ul sau de programul care executã query-ul. Parametri formali al unui query sunt reprezentate de obiecte Parameter în colectia Parameters al QueryDef-ului.
Recordsets
Obiectul Recordset
este diferit de obiectele DAO prezentate pânã acum, prin faptul
ca acesta existã atâta timp cât aplicatia ruleazã.
Un obiect Recordset reprezintã,
în memorie, un set de articole dintr-una sau mai multe tabele. Obiectele
Recordset sunt unele dintre
cele mai puternice construite în Microsoft Jet, deoarece acestea ne permit
sã accesãm din program nu numai tabele native Microsoft Jet, ci
si tabele ISAM, cum ar fi Microsoft FoxPro sau surse de date ODBC cum ar fi
Microsoft SQL Server. În plus, obiectele Recordset pot fi bazate pe query-uri
care contin multiple tabele din surse de eterogene.
Colectia Recordsets contine toate obiectele Recordset deschise în obiectul
Database curent. Subliniem
încã odatã, cã obiectele Recordset sunt obiecte pe care le putem deschide doare din cod. De exemplu,
când dorim sã vizualizãm o tabelã în Access
cu ajutorul interfetei utilizator, atunci aceastã tabelã nu este
un obiect Recordset. În
acest caz, Microsoft Jet creazã un obiect recordset pentru a accesa datele,
dar acest recordset nu face parte din colectia Recordsets.
Relations
Microsoft Jet furnizeazã facilitãti puternice de integritate relationalã si referntialã, folosind relatiile. Un obiect Relation reprezintã o relatie între coloanele dintre douã sau mai multe tabel. Colectia Relations contine toate obiectele Relation pentru un obiect Database dat.
Containers
Una dintre cerintele importante ale engine-ului este faptul cã trebuie sã pãstreze independenta aplicatiei: engine-ul nu trebuie sã fie specific unei anumite aplicatii. În oroce caz, Microsft Jet furnizeayã o colectie de obiecte si obiecte generice, astfel încât o aplicatie poate sã-si stocheze obiectele în baza de date. Acest obiect generic este cunoscut cs fiind un container. Colectia Containers pãstreazã toate obiectele container pentru un obiect DataBase. Ca un exemplu, Microsoft Access se bazeazã pe Microsoft Jet pentru a-i stoca obiectele specifice aplicatiei, cum ar fi form-urile, macro-urile si modulele. Microsoft Jet stocheazã aceste obiecte strãine cu ajutorul colectiei Containers.
Documents
Obiectul Document reprezintã un anumit obiect în colectia Documents. În paragraful anterior, am dat un exemplu în care Microsoft Access folosea colectia Containers pentru a-si organiza propriile obiecte. Obiectul Document stocheazã o instantã specificã al unui obiect specific aplicatiei. De exemplu, când Microsoft Access creeazã o bazã de date, el creeazã o varietate de obiecte Container, un obiect pentru form-uri, altul pentru rapoarte, si asa mai departe. Cum utilizatorul creazã form-uri (machete), acestea sunt stocate în obiecte Document individuale în containerul Forms adãugat bazei de date de Microsoft Access.
Properties
Fiecare obiect DAO are o colectie Properties. Un obiect Property
contine informatii caracteristice unui anumit obiect. Noi putem citi valorile
acestor proprietãti pentru a obtine informatii despre un anumit obiect
sau putem seta o proprietate pentru a defini caracteristicile obiectului. De
asemenea putem sã ne definim propriile proprietãti.
Cu aceastã
descriere destul de detaliatã, credem noi, sperãm cã ati
înteles cât de cât ce este DAO, si ce putem face cu el. Citind
în continuare articolul, sperãm sã întelegeti si mai
bine.
Fundamentele DAO
Acum, fiind familiarizati cu tipurile de obiecte reprezentate în DAO, este timpul sã trecem la bazele utilizãrii DAO. În ceea ce urmeazã, vom prezenta cum se lucreazã cu obiectele si colectiile DAO, cum sã referim aceste obiecte, si cum sã reprezentãm obiecte utilizând variabile.
Obiecte si colectii
Asa dupã cum am vãzut din discutarea ierarhiei DAO,
conceptele de obiect si colectie sunt foarte importante. Cele mai multe tipuri
de obiecte au colectii ce contin fiecare dintre tipurile membrilor. De exemplu,
colectia TableDefs reprezintã
un set al tuturor obiectelor tabelã din baza de date si contine toate
obiectele individuale TableDefs.
De obicei ne referim la un obiect prin ierarhia de colectie; se porneste cu
obiectul DBEngine apoi se
continuã calea prin ierarhie:
DBEngine.ColectiaParinte.ColectiaFiu!Nume
Existã patru forme sintactice utilizate
pentru a face referire la un obiect dintr-o colectie:
• Colectia!Nume, sau Colectia![Nume]
dacã obiectul Nume contine caractere non-standard, cum ar fi spatiile
de exemplu
• Colectia(“Nume”)
• Colectia(string) unde
string este o expresie sau
o variabilã ce contine numele obiectului
• Colectia(index) unde index este
pozitia obiectului în cadrul colectiei
Utilizând prima formã, sintaxa Colectia!Nume sau Colectia![Nume],
vã puteti referi direct la un obiect prin numele sãu. Aceastã
formã este mai compactã si face ca referirile lungi ale unor obiecte
sã fie mai usor de citit decât în alte forme. De exemplu,
comparati cele douã referiri care urmeazã:
TableDefs(“Clienti”).Indexes(“PrimaryKey”).Fields(“Nume”)
TableDefs! Clienti.Indexes!PrimaryKey.Fields!Nume
Cu forma a doua, sintaxa Colectia(“Nume”), puteti sã referiti un obiect utilizând o expresie string.
Urmãtoarele douã exemple sunt echivalente:
TableDefs(“Clienti”)
TableDefs(“Clie” & “nti”)
Utilizând forma treia, sintaxa Colectia(string), puteti referi un obiect utilizând o variabilã:
Dim strNume As String
strNume = “Clienti”
TableDefs(strNume)
Cu forma a patra, sintaxa Colectia(index), puteti face referire la un obiect în functie de pozitia sa
în colectie. De exemplu:
‘Tipãreste
primele zece nume TableDef.
For intX = 0 To 9
Debug.Print
Workspaces(0).Databases(0).TableDefs(intX).Name
Next intX
Indecsii în colectiile DAO sunt bazati pe zero, adicã primul element într-o colectie este zero.
Utilizarea sintaxei semn de exclamare (!) si punct (.)
În sintaxa DAO, când se face referire la un obiect, acesta
se desparte de celãlalt obiect la care se referã utilizând
caracterul semn de exclamare (!) sau caracterul punct (.). Utilizarea unuia
sau a altuia din cele douã caractere depinde de contextul în care
se utilizeazã.
• Folositi punctul pentru a face referire la un membru
sau la o proprietate care este creatã cu Microsoft Jet.
• Folositi
semnul exclamãrii pentru a vã referi la un membru sau o proprietate
pe care ati creat-o dvs. singuri.
Determinarea limitelor colectiilor
În exemplul anterior, care listeazã numele primelor 10
TableDef-uri, se presupune cã existã cel putin 10 tabele în
baza de date si aceastã secventã nu oferã posibilitatea
de a afisa toate numele tabelelor. Dacã se lucreazã efectiv cu
colectii, este important de înteles cum sunt acestea ordonate si cum se
pot determina limitele lor.
Pentru a determina limitele colectiilor, se poate folosi proprietatea
Count a colectiilor. Valoarea
acestei proprietãti reflectã numãrul de obiecte din colectia
respectivã, de exemplu dacã proprietatea Count a unei colectii are valoarea 6 atunci vor fi 6 obiecte în colectia
respectivã. Datoritã faptului cã colectiile DAO sunt bazate-zero,
adicã primul obiect din colectie va ocupa pozitia 0, când se va
face comparatia cu indexul pozitiei curente va trebui sã se scadã
din Count valoarea 1. Urmãtorul exemplu va tipãri numele tuturor
tabelelor din baza de date folosind proprietatea Count.
For intX = 0 to Workspaces (0).Databases
(0).TableDefs. Count - 1
Debug. Print Workspaces (0).Databases (0). TableDefs
(intX). Name
Next intX
În acest exemplu se observã cum se scade 1 din proprietatea
Count pentru a functiona corect comparatia. Aceastã problemã se
poate evita folosind structura For Each în locul ciclului For…Next. Urmãtoarea secventã de cod realizeazã acelasi
lucru ca cea anterioarã, dar acum nu se mai verificã explicit
limitele colectiei.
For Each tbl In Workspaces
(0). Databases (0).TableDefs
Debug. tbl.Name
Next tbl
Când unul din obiecte este sters proprietatea Count pentru colectia respectivã este decrementatã.
Colectii implicite
Aproape toate obiectele DAO au colectii implicite. De exemplu, colectia implicitã pentru obiectul Workspace este Databases. Folosind sintaxa normalã, se poate face referire la o bazã de date în urmãtorul mod: DBEngine.Work spaces(0).Databases(0). Folosind colectiile implicite ale obiectului WorkSpace aceastã linie se poate scrie mai scurt astfel: DBEngine.Workspaces(0). De asemenea colectia implicitã a obiectului DBEngine este Workspaces, si folosind acest lucru linia de mai sus se poate scrie într-o formã si mai scurtã: DBEngine(0).
Setarea si utilizarea variabilelor obiect
Lucrul cu DAO poate duce uneori la situatia ca secventele de cod sã
devinã greoaie datoritã referirii dese la obiecte prin specificarea
pozitiei lor în cadrul ierarhiei DAO. De exemplu, vom considera secventa
de cod ce afiseazã numele tuturor câmpurilor din tabela Clienti:
Function AfisareNumeCampuri()
Dim intX As
Integer
For intX= 0 To DBEngine(0)(0).TableDefs(“Clienti”)._
Fields.Count-1
Debug.Print DBEngine(0)(0).TableDefs(“Clienti”)._
Felds(intX).Name
Next intX
End Function
Acest tip de programare prezintã douã dezavantaje. Primul
este acela cã trebuie introduse si întretinute linii de cod lungi
datoritã referirii la obiecte. A doua problemã constã în
faptul cã performanta aplicatiei va suferi, pentru cã fiecare
referinta din cadrul ierarhiei este parcursã si rezolvatã. Solutia
acestor probleme este utilizarea variabilele obiect.
Variabilele obiect sunt un tip special de variabile suportate de VBA;
prin utilizarea lor se seteazã referinta spre obiect doar o datã,
iar apoi se va face referirea la variabila obiect în locul unei referiri
explicite în ierarhia DAO. Fiecarui tip de obiect DAO îi corespunde
un tip de variabilã obiect. De exemplu, obiectului Workspace îi corespunde o variabilã obiect de tip workspace, obiectului
Database îi corespunde
o variabilã de tip database, s.a.m.d. Pentru utilizarea variabilelor
obiect, trebuie declarat prima datã tipul de variabilã iar apoi
îi trebuie asociat un obiect. Forma generalã a declaratiei este
Dim NumeVariabila
As NumeObiect
Set NumeVariabila=ObiectDAO
Folosind variabilele obiect, exemplul anterior se va modifica astfel:
Function AfisareImbunatatitaNumeCampuri()
Dim intX as Integer
Dim tblClienti As TableDef
Set tblClienti
=DBEngine(0).(0).TableDefs(“Clienti”)
For intX=0 To tblClienti.Fields.Count -1
Debug.Print
tblClienti.Fields(intX).Name
Next intX
End Function
Comparând cele douã variante de cod vom observa cã variabilele obiect permit un stil de programare ce reduce numãrul de referinte directe la obiecte, iar codul este usor de citit si de întretinut. În plus, pentru cã Microsoft Jet face o referintã la tabela Clienti doar o singurã datã, codul va rula mai repede. Este important de retinut cã variabilele obiect diferã de variabilele obisnuite, pentru cã ele nu au o valoare intrinsecã, ci fac referire la reprezentarea unui obiect din memorie; de asemenea, toate variabilele obiect ce sunt atasate unui obiect fac referire la aceeasi instantã.