Încărcarea asincronă a datelor cu ado în delphi

În unele cazuri, trebuie să efectuăm încărcarea asincronă a datelor din baza de date. La urma urmei, utilizatorul poate vedea aproape imediat primele fragmente de date pe măsură ce se încarcă, fără a aștepta descărcarea completă. De asemenea, utilizatorul va putea să anuleze descărcarea oricând va apărea. Și, desigur, încărcarea asincronă vă permite să faceți, de exemplu, o interfață utilizator cu mai multe tab-uri, în fiecare filă din care puteți descărca simultan date diferite. În acest articol voi da o soluție care vă va permite să efectuați o încărcare asincronă pas-cu-pas a datelor într-o masă în Delphi folosind ADO.

Crearea unui proiect

De fapt, în ADO, totul este gata pentru încărcarea asincronă a datelor, trebuie doar să setați anumite opțiuni și să procesați evenimentele necesare. Dar în Delphi totul nu era atât de simplu. Pentru a afișa datele din tabel este utilizat TDBGrid Delphi moștenit de la TCustomDBGrid (sau de dezvoltare terțe părți multiple, de asemenea, moștenită de la TCustomDBGrid), referindu-se la TDataSource obiect, care, la rândul său, se referă la TDataSet. Iar atunci când se lucrează cu ADO, trebuie să utilizați un înveliș TADOStoredProc, TADOQuery, TADOTable și TADODataSet, care sunt moștenite de la obiect TDataSet. Doar aceste ambalaje și nu dau în plină forță pentru a utiliza încărcarea asincronă a datelor. Pentru a înțelege ce funcționează și ce nu funcționează atunci când utilizați aceste împachetări, să facem un exemplu simplu cu utilizarea lor.

Acum, în Delphi, vom face un nou proiect cu formularul VCL (elementul de meniu File -> New -> VCL Forms Application - Delphi), puneți tabelul TDBGrid și două butoane TButton pe formular. Un buton va fi pentru a începe descărcarea, iar al doilea pentru a anula descărcarea. Voi da nume butoanelor - ButtonLoad și ButtonCancel. Toate celelalte nume vor rămâne neschimbate. Butonul de anulare implicită este dezactivat, Enabled este setat la False. De asemenea, specificăm antetul formularului și textul de pe butoane. Voi adăuga, de asemenea, o componentă TProgressBar care ne va spune dacă procesul de descărcare este în desfășurare sau nu și componenta TLabel pentru a afișa numărul de înregistrări descărcate. Proprietatea Style a barei de progres este setată la pbstMarquee și Visible to False.

După o parte vizuală a formularului este completat, a pus componentele TDataSource formă și TADOQuery TADOConnection. Acum, trebuie să asociați tabelul TDBGrid (ne-a luat DBGrid1 nume) cu sursa de date TDataSource (în cazul nostru este numit DataSource1), sursa de date - o TADOQuery cerere (ne-am numit-o ADOQuery1), iar cererea - cu conexiune TADOConnection (noi se numește ADOConnecție1). Ie se pare că este o astfel de conexiune: DBGrid1 -> DataSource1 -> ADOQuery1 -> ADOConnection1. Pentru acest set y tabelul de la sursa de date de proprietate DataSource1, sursa de date DataSet proprietate ADOQuery1 egală, o proprietate de solicitare de conectare la ADOConnection1.

Încărcarea asincronă a datelor cu ado în delphi

Acum trebuie să setați proprietățile conexiunii în proprietatea ConnectionString a obiectului ADOConnection1. La mine va fi următoarea linie:

Aici am specificat imediat numele de utilizator și parola, astfel încât să puteți dezactiva fereastra standard pentru a solicita un nume de utilizator și o parolă prin setarea proprietății LoginPrompt a componentei ADOConnection1 la False.

Acum vom gândi la o astfel de solicitare, care va fi executată pentru o lungă perioadă de timp, și o vom scrie în proprietatea SQL a componentei ADOQuery1. În același timp, vom verifica câte date vor fi încărcate pentru fiecare dintre opțiunile de încărcare. Am făcut această solicitare:

La mine această solicitare în SQL Management Stodio a fost executată timp de 1 minut și 9 secunde.

O interogare de date sincronă simplă în Delphi cu ADO

În primul rând, vom face o cerere simplă de date sincronă. Vom executa interogarea cu privire la evenimentul OnClick de la ButtonLoad. Aici este codul pentru a executa interogarea:

Încărcarea asincronă a datelor cu ado în delphi

Simplă interogare de date asincrone în Delphi cu ADO

Acum, să încercăm această interogare în mod asincron. Pentru aceasta, setați proprietatea ExecuteOptions a componentei ADOQuery1 la pavilionul eoAcyncExecute în True. Și pentru a vă conecta și la DBMS, asincron, setați proprietatea ConnecOptions la coAsyncConnect. Numărul de intrări va trebui să fie afișat acum numai după executarea interogării. Acest lucru poate fi învățat din evenimentul AfterOpen al componentei ADOQuery1. Erori pot fi surprinse de evenimentul OnExecuteComplete al componentei ADOConnection1. În timp ce cererea este procesată, vom afișa bara de progres, butonul "Anulare" este activ și butonul "Descărcare" este inactiv. Anulează interogarea care rulează așa cum ar trebui să fie în ADO - sunând la funcția Anulare. Iată cum arată codul:

Încărcarea asincronă a datelor cu ado în delphi

Dezinstalați o cerere de date asincronă simplă în Delphi utilizând ADO

Descărcarea de la exemplul de mai sus funcționează bine până când faceți clic pe butonul "Anulare". Există 2 probleme aici:

    1. Când datele au început deja să se încarce pe client, anularea nu funcționează. În loc de a anula, programul se blochează pe linia "ADOQuery1.Recordset.Cancel;" până când toate datele sunt încărcate complet.
    2. După ce apelați funcția "ADOQuery1.Recordset.Cancel;" (dacă cererea a fost anulată, desigur, consultați pasul 1), nu va fi posibilă re-executarea cererii. apelul la metoda ADOQuery1.Open; nu face nicio acțiune. Acest lucru se datorează faptului că componenta ADOQuery1 rămâne închisă (Active = False), dar în același timp starea acesteia indică deschiderea cererii (State = dsOpening). Acest lucru arată clar că pachetul VCL peste ADO nu acceptă anularea.

Prima problemă poate fi încercată în trei moduri:

    1. Modificați driverul dacă aveți un alt driver. Dar se poate întâmpla ca driverul de care aveți nevoie să nu existe sau baza de date să nu accepte anularea cererilor.
    2. Utilizați cursorul serverului (trebuie să setați proprietatea CursorLocation din clUseServer pentru componenta ADOQuery1). Dar, cu cursorul serverului, nu puteți cunoaște numărul de înregistrări și aveți nevoie de o conexiune permanentă la DBMS pentru a afișa datele. Prin urmare, pentru a lucra cu datele de pe client, trebuie să le copiați în memoria RAM (de exemplu, în componenta TClientDataSet) sau în baza de date locală dacă volumul de date este foarte mare. Și citirea tuturor datelor de pe cursorul serverului este lentă.
    3. Efectuați o oprire a descărcării. Ie pentru a arăta utilizatorului că cererea a fost anulată, dar, de fapt, să dea cererea de a executa până la sfârșit și numai după aceea ștergeți-o. Puteți șterge cu siguranță componente TADOQuery la timpul de boot (este posibil, dacă setați la pavilion eoAsyncFetchNonBlocking Adevărat), dar descărcarea de date ADO obiecte în același timp, nu se oprește, va continua. Acest lucru poate fi văzut chiar și în managerul de sarcini. În plus, atunci când eliminați componentele TADOQuery în timpul de boot eșuează intermitent «violare de acces la 0x1cbaf811: citește de adresa 0x00000000» undeva în măruntaiele OAD.

A doua problemă nu poate fi evitată. Există o singură soluție aici - după fiecare anulare (sau cel mult de fiecare dată), pentru fiecare interogare nouă, să creați o nouă componentă TADOQuery și să ștergeți componenta existentă imediat sau mai târziu când aplicația se termină.

Având în vedere problemele care au apărut odată cu anularea problemei, codul formularului se va schimba foarte mult. Voi elimina componentele ADOQuery1 și ADOConnection1 din formular și le voi crea de fiecare dată când descărc datele. Mai jos voi da două exemple și le voi descrie dezavantajele.

Iată primul exemplu. Aici folosesc cursorul pentru a prelua datele. Pentru a afișa, am copia datele în componenta TClientDataSet. Anularea descărcării aici funcționează excelent. Dar există și alte probleme, care vor fi scrise mai jos.

Încărcarea asincronă a datelor cu ado în delphi

Prin urmare, dacă trebuie să descărcați o cantitate mare de date pe computerul unui utilizator, trebuie să căutați un alt mod. Exemplul de mai sus de încărcare și stocare a datelor în RAM este adecvat numai pentru volume mici.

Încărcarea datelor asincrone pas cu pas în Delphi utilizând ADO

Semnificația descărcării pas cu pas constă în faptul că utilizatorul nu trebuie să aștepte până la sfârșitul interogării pentru a vedea datele. Imediat ce prima parte a datelor este încărcată, aceasta poate fi deja afișată în tabel. După aceea, pe măsură ce încărcați din ce în ce mai multe date noi, trebuie să le afișați și în tabel. Astfel, utilizatorul poate începe vizualizarea tabelului aproape imediat după începerea descărcării și va vedea dinamica descărcării.

Există două opțiuni pentru a face acest lucru. Prima opțiune este o mică modificare a exemplului anterior, unde descărcarea provine de la cursorul serverului. Semnificația modificării este că trebuie să legăm imediat tabelul de componenta TClientDataSet și ca componenta TClientDataSet umple, tabelul va afișa imediat înregistrările noi. Aici se vor schimba numai metodele AfterOpen și WndMethod:

A doua opțiune - este de a instala pavilion eoAsyncFetchNonBlocking la True în componenta TADOQuery și datele de încărcare progresivă în eveniment OnFetchProgress. Această metodă funcționează de 10 ori mai rapidă decât cea precedentă. Cu toate acestea, aici am fost confruntat cu o altă problemă: atunci când datele unui eveniment de probă OnFetchProgress nu poate fi setat cursorul la prima înregistrare (sau metoda de apeluri în prima prealabilă nu a ajutat) și, ca urmare, vom prelua toate înregistrările cu excepția primei. Pentru a evita acest lucru, vom descărca datele direct folosind ADO. Exemplul se va schimba puternic, așadar voi da aici textul integral:

Încărcarea asincronă pas cu pas a mai multor seturi de date în Delphi utilizând ADO

Dacă trebuie să încărcați mai multe seturi de date în mod asincron ca în exemplul anterior, atunci nici nu puteți încerca să faceți acest lucru. Faptul este că, atunci când trece la următorul set de date cu ajutorul «query.Recordset: = query.NextRecordset (recordsAffected);», în acest moment, componenta TADOQuery se închide un cursor și mai mult vei primi nimic. Da, aceasta funcționează bine pentru solicitări sincrone, dar nu pentru evenimentul OnFetchProgress. Un exemplu de lectură de la cursorul serverului nu va funcționa nici.

Articole similare