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ã.