Working with Databases/ro: Difference between revisions
No edit summary |
No edit summary |
||
Line 1: | Line 1: | ||
[[Category:Learning]] | |||
= | = Lucrul cu baze de date = | ||
== Generalități == | |||
Bazele de date sunt o parte integrantă chiar și pentru cele mai simple aplicații moderne. Deși mulți asociază bazele de date cu site-urile web, ele sunt folosite și pentru aplicații desktop. Qt permite stocarea datelor folosind baze de date. Qt oferă un modul pentru baze de date relaționale numit "QtSql":http://doc.qt.nokia.com/4.7-snapshot/qtsql.html. "SQL ":http://en.wikipedia.org/wiki/SQL este limbajul folosit pentru manipularea unor baze de date relaționale. Folosind SQL putem comunica între diferite baze de date și aplicație propriu-zis. | |||
Modului "QtSql ":http://doc.qt.nokia.com/4.7-snapshot/qtsql.html oferă drivere pentru a comunica cu diferite API-uri de baze de date. De vreme ce API-ul modulului '''QtSql''' este independent de API-ul bazelor de date, tot codul care ține de lucrul cu baze de date este conținut de aceste drivere. O multitudine de drivere sunt oferite împreună cu Qt, iar altele pot fi adăugate. | |||
Următorul tabel conține o listă cu driverele incluse în Qt. Datorită unor incompatibilități cu licența "GPL":http://en.wikipedia.org/wiki/GPL, nu toate driverele sunt oferite împreună cu versiunile open-source ale lui Qt. | |||
[[Image:https://lh6.googleusercontent.com/-1gywxJ7snT8/TiMY9j9wdGI/AAAAAAAAAOY/cxd2E5sxaRo/drivere%20SQL.JPG|https://lh6.googleusercontent.com/-1gywxJ7snT8/TiMY9j9wdGI/AAAAAAAAAOY/cxd2E5sxaRo/drivere%20SQL.JPG]]<br />'''Driverele disponibile pentru a comunica cu API-uri de baze de date''' | |||
Driverul pentru '''SQLite''' este mai bine pus punct și este disponibil pentru toate platformele. Driverele pentru Oracle, PostreSQL,MySQL și ODBC sunt adresate în special pentru Windows și Linux. | |||
== Conectarea la baze de date == | |||
Pentru a accesa o bază de date cu un obiect "QSqlQuery&quot;:http://doc.qt.nokia.com/4.7-snapshot/qsqlquery.html sau "QSqlQueryModel&quot;:http://doc.qt.nokia.com/4.7-snapshot/qsqlquerymodel.html trebuie ca mai întâi să stabilim și să deschidem niște conexiuni cu niște baze de date. Conexiunile se identifică prin numele conexiunii ci nu numele bazei de date. Pot exista mai multe conexiuni la aceeași bază de date. QSqlDatabase oferă suport pentru conceptul de conexiune implicită, care este o conexiune fără nume. Atunci când apelăm funcţii ale unor obiecte '''QSqlQuery''' sau '''QSqlQueryModel''' fără să specificăm un nume de conexiune, se va utiliza conexiunea implicită. Crearea unor conexiuni implicite este recomandată atunci când aplicaţia necesită doar o singură conexiune la o bază de date. | |||
Există o diferenţă între a crea o conexiune şi a o deschide. Crearea unei conexiuni presupune crearea unei instanţe a clasei "QSqlDatabase&quot;:http://doc.qt.nokia.com/4.7-snapshot/qsqldatabase.html . Conexiunea nu este utilizabilă până când nu este deschisă. Următorul cod ne arată cum putem crea o conexiune, iar mai apoi cum putem să o deschidem: | |||
== | <code> myDb = QSqlDatabase::addDatabase("QODBC&quot;, "MyDbConnectionName&quot;);<br /> myDb.setDatabaseName(<br /> "Driver={Microsoft Access Driver (*.mdb)};FIL={MS Access};DBQ=myDb.mdb&quot;);<br /> if (myDb.open() == false) {<br /> QMessageBox::critical(0,"Critical Error!",<br /> "Could not connect to myDb.mdb."<br /> + myDb.lastError().text());<br /> }</code> | ||
În cazul de mai sus am creat o conexiune cu ajutorul driverului QODBC cu numele '''MyDbConnectionName'''. Mai apoi setăm numele bazei de date. De reținut că numele bazei de date este diferit de numele conexiunii. Baza de date pe care o deschidem în acest caz este o bază de date Access. După ce am setat un nume pentru baza de date urmează să încercăm să deschidem baza de date. Daca acest lucru nu a fost posibil vom afișa un mesaj de eroare prin care să semnalăm eroare întâmpinată. | |||
Pentru a executa un query | == Executarea unor interogări SQL == | ||
Clasa "QSqlQuery&quot;:http://doc.qt.nokia.com/4.7-snapshot/qsqlquery.html oferă o interfață pentru executarea unor interogări SQL și navigare prin setul de rezultate al interogării. Clasele "QSqlQueryModel ":http://doc.qt.nokia.com/4.7-snapshot/qsqlquerymodel.html și "QSqlTableModel ":http://doc.qt.nokia.com/4.7-snapshot/qsqltablemodel.html oferă un suport de un nivel mai înalt pentru accesarea unei baze de date. | |||
Pentru a executa un query SQL putem crea un obiect de tip '''QSqlQuery''' iar mai apoi apelăm metoda "bool exec&amp;#40;QString &query;&#41;":http://doc.qt.nokia.com/4.7-snapshot/qsqlquery.html#exec precum în următorul exemplu : | |||
<code> QSqlQuery query(QSqlDatabase::database("MyDbConnectionName&quot;));<br /> query.exec&amp;#40;"SELECT ID FROM PROFILE ORDER BY ID ASC&quot;&#41;;</code> | |||
Constructorul obiectului '''QSqlQuery''' primește ca argument conexiunea la baza de date care va fi folosită. Dacă nu am fi specificat-o s-ar fi folosit conexiunea implicită. | Constructorul obiectului '''QSqlQuery''' primește ca argument conexiunea la baza de date care va fi folosită. Dacă nu am fi specificat-o s-ar fi folosit conexiunea implicită. | ||
'''QSqlQuery''' ne permite să accesăm rezultate doar pe rând. După ce executăm metoda '''exec | '''QSqlQuery''' ne permite să accesăm rezultate doar pe rând. După ce executăm metoda '''exec&amp;#40;&#41;''', pointerul intern al lui '''QSqlQuery''' este localizat cu o poziție în urmă față de prima înregistrare. Pentru a avansa în setul de rezultate trebuie să apelăm metoda "bool next()":http://doc.qt.nokia.com/4.7-snapshot/qsqlquery.html#next. În exemplul următor se iterează peste rezultatele unei interogări : | ||
<code> while (query.next()) {<br /> id = query.value(0).toInt();<br /> if (id == free_id) {free_id++;<br /> } else {return free_id;}<br /> }</code> | |||
Funcția "QVariant value(int index) const&quot;:http://doc.qt.nokia.com/4.7-snapshot/qsqlquery.html#value returnează valoară câmpului cu indexul specificat din înregistrarea curentă. Numerotarea indexurilor câmpurilor începe de la zero. El returnează această valoare ca un "QVariant&quot;:http://doc.qt.nokia.com/4.7-snapshot/qvariant.html, un tip de date care poate păstra diverse tipuri precum '''int''', '''QString''' sau '''QByteArray'''. În cazul din codul de mai sus folosim funcția "int toInt(bool* ok=0)const&quot;:http://doc.qt.nokia.com/4.7-snapshot/qvariant.html#toInt pentru a converti această valoare într-un '''int'''. | |||
Dar putem itera atât înainte cât și înapoi folosind : "next()":http://doc.qt.nokia.com/4.7-snapshot/qsqlquery.html#next, "previous()":http://doc.qt.nokia.com/4.7-snapshot/qsqlquery.html#previous, "first()":http://doc.qt.nokia.com/4.7-snapshot/qsqlquery.html#first, "last()":http://doc.qt.nokia.com/4.7-snapshot/qsqlquery.html#last și "seek()":http://doc.qt.nokia.com/4.7-snapshot/qsqlquery.html#seek. Indexul înregistrării curente este returnat de funcția&quot; int at() const&quot;:http://doc.qt.nokia.com/4.7-snapshot/qsqlquery.html#at, iar numărul total de înregistrări din setul de rezultate se obține apelând funcția "int size() const&quot;:http://doc.qt.nokia.com/4.7-snapshot/qsqlquery.html#size. | |||
Pentru a deternina dacă un anumit driver posedă o anumită trăsătură apelăm funcția "bool QSqlDriver::hasFeature()":http://doc.qt.nokia.com/4.7-snapshot/qsqldriver.html#hasFeature. Dacă iterăm printr-un set de rezultate folosind doar '''next()''' și '''seek()''' este recomandat să folosim funcția "QSqlQuery::setForwardOnly(true)":http://doc.qt.nokia.com/4.7-snapshot/qsqlquery.html#setForwardOnly înainte de a apela '''exec&amp;#40;&#41;'''. Aceasta este o optimizare simplă prin care mărim viteza unor interogări mai ales în cazul în care lucrăm cu seturi mari de rezultate. | |||
Un exemplu în care se folosesc substituenți cu nume poate fi văzut în următoarea secvență de cod : | '''QSqlQuery''' poate executa orice tip de interogare SQL, nu doar '''SELECT'''<s>uri. Dacă dorim să inserăm mai multe valori deodată, este mai eficient să separăm interogarea de valorile ce urmează să le inserăm. Acest lucru poate fi făcut prin intermediul unor substituenți. Qt oferă suport pentru două tipuri de substituenți :<br />* '''substituenți cu nume''' și<br />* '''substituenți poziționali'''. | ||
<br />Un exemplu în care se folosesc substituenți cu nume poate fi văzut în următoarea secvență de cod : | |||
<br /><code> QSqlQuery query(QSqlDatabase::database("MyDbConnectionName&quot;));<br /> query.prepare("INSERT INTO PROFILE&quot;<br /> " (Id,Name)"<br /> " VALUES (:Id,:Name)");<br /> query.bindValue(":Id&quot;, profile</s>>getId());<br /> query.bindValue(":Name&quot;, profile->getName());<br /> query.exec&amp;#40;&#41;;</code> | |||
==Utilizarea unui model | == Utilizarea unui model SQL == | ||
Pe lângă '''QSqlQuery''', Qt oferă clase de nivel înalt pentru accesarea bazelor de date. Aceste clase sunt: | Pe lângă '''QSqlQuery''', Qt oferă clase de nivel înalt pentru accesarea bazelor de date. Aceste clase sunt: | ||
* | * "QSqlQueryModel&quot;:http://doc.qt.nokia.com/4.7-snapshot/qsqlquerymodel.html; | ||
* | * "QSqlTableModel&quot;:http://doc.qt.nokia.com/4.7-snapshot/qsqltablemodel.html; | ||
* | * "QSqlRelationalTableModel&quot;:http://doc.qt.nokia.com/4.7-snapshot/qsqlrelationaltablemodel.html. | ||
Aceste clase ușurează prezentarea datelor dintr-o bază de date într-o vizualizare de prezentare a datelor precum | Aceste clase ușurează prezentarea datelor dintr-o bază de date într-o vizualizare de prezentare a datelor precum "QListView&quot;:http://doc.qt.nokia.com/4.7-snapshot/qlistview.html sau "QTableView&quot;:http://doc.qt.nokia.com/4.7-snapshot/qtableview.html. | ||
* | * "QSqlQueryModel&quot;:http://doc.qt.nokia.com/4.7-snapshot/qsqlquerymodel.html oferă un model care poate fi doar citit bazat pe o interogare SQL. Un exemplu de folosire îl aveți mai jos : | ||
<code> myModel = new QSqlQueryModel(this);<br /> myModel->setQuery("SELECT * FROM PROFILE&quot;,<br /> QSqlDatabase::database("MyDbConnectionName&quot;));</code> | |||
* "QSqlTableModel&quot;:http://doc.qt.nokia.com/4.7-snapshot/qsqltablemodel.html oferă un model editabil pentru un singur tabel dintr-o bază de date. Nu presupune cunostințe de sintaxă SQL. Tabelul se selectează prin apelul funcției "void setTable(const QString&amp; tableName)":http://doc.qt.nokia.com/4.7-snapshot/qsqltablemodel.html#setTable. Mai apoi putem apela la filtre sau sorta după o anumită coloană precum în exemplul următor : | |||
<code> QSqlTableModel model;<br /> model.setTable("PROFILE&quot;);<br /> model.setFilter("Age > 50&quot;);<br /> model.setSort(2, Qt::DescendingOrder);<br /> model.select();</code> | |||
"QSqlRelationalTableModel&quot;:http://doc.qt.nokia.com/4.7-snapshot/qsqlrelationaltablemodel.html oferă suport pentru chei externe. O cheie externă este o relație de unu la unu între un câmp dintr-un tabel la cheia primară a unui alt tabel. De exemplu daca tabelul book are un câmp numit authorid care indifică câmpul id de al tabelului author, spunem că authorid este o cheie externă. |
Revision as of 11:09, 24 February 2015
Lucrul cu baze de date
Generalități
Bazele de date sunt o parte integrantă chiar și pentru cele mai simple aplicații moderne. Deși mulți asociază bazele de date cu site-urile web, ele sunt folosite și pentru aplicații desktop. Qt permite stocarea datelor folosind baze de date. Qt oferă un modul pentru baze de date relaționale numit "QtSql":http://doc.qt.nokia.com/4.7-snapshot/qtsql.html. "SQL ":http://en.wikipedia.org/wiki/SQL este limbajul folosit pentru manipularea unor baze de date relaționale. Folosind SQL putem comunica între diferite baze de date și aplicație propriu-zis.
Modului "QtSql ":http://doc.qt.nokia.com/4.7-snapshot/qtsql.html oferă drivere pentru a comunica cu diferite API-uri de baze de date. De vreme ce API-ul modulului QtSql este independent de API-ul bazelor de date, tot codul care ține de lucrul cu baze de date este conținut de aceste drivere. O multitudine de drivere sunt oferite împreună cu Qt, iar altele pot fi adăugate.
Următorul tabel conține o listă cu driverele incluse în Qt. Datorită unor incompatibilități cu licența "GPL":http://en.wikipedia.org/wiki/GPL, nu toate driverele sunt oferite împreună cu versiunile open-source ale lui Qt.
https://lh6.googleusercontent.com/-1gywxJ7snT8/TiMY9j9wdGI/AAAAAAAAAOY/cxd2E5sxaRo/drivere%20SQL.JPG
Driverele disponibile pentru a comunica cu API-uri de baze de date
Driverul pentru SQLite este mai bine pus punct și este disponibil pentru toate platformele. Driverele pentru Oracle, PostreSQL,MySQL și ODBC sunt adresate în special pentru Windows și Linux.
Conectarea la baze de date
Pentru a accesa o bază de date cu un obiect "QSqlQuery":http://doc.qt.nokia.com/4.7-snapshot/qsqlquery.html sau "QSqlQueryModel":http://doc.qt.nokia.com/4.7-snapshot/qsqlquerymodel.html trebuie ca mai întâi să stabilim și să deschidem niște conexiuni cu niște baze de date. Conexiunile se identifică prin numele conexiunii ci nu numele bazei de date. Pot exista mai multe conexiuni la aceeași bază de date. QSqlDatabase oferă suport pentru conceptul de conexiune implicită, care este o conexiune fără nume. Atunci când apelăm funcţii ale unor obiecte QSqlQuery sau QSqlQueryModel fără să specificăm un nume de conexiune, se va utiliza conexiunea implicită. Crearea unor conexiuni implicite este recomandată atunci când aplicaţia necesită doar o singură conexiune la o bază de date.
Există o diferenţă între a crea o conexiune şi a o deschide. Crearea unei conexiuni presupune crearea unei instanţe a clasei "QSqlDatabase":http://doc.qt.nokia.com/4.7-snapshot/qsqldatabase.html . Conexiunea nu este utilizabilă până când nu este deschisă. Următorul cod ne arată cum putem crea o conexiune, iar mai apoi cum putem să o deschidem:
myDb = QSqlDatabase::addDatabase("QODBC&quot;, "MyDbConnectionName&quot;);<br /> myDb.setDatabaseName(<br /> "Driver={Microsoft Access Driver (*.mdb)};FIL={MS Access};DBQ=myDb.mdb&quot;);<br /> if (myDb.open() == false) {<br /> QMessageBox::critical(0,"Critical Error!",<br /> "Could not connect to myDb.mdb."<br /> + myDb.lastError().text());<br /> }
În cazul de mai sus am creat o conexiune cu ajutorul driverului QODBC cu numele MyDbConnectionName. Mai apoi setăm numele bazei de date. De reținut că numele bazei de date este diferit de numele conexiunii. Baza de date pe care o deschidem în acest caz este o bază de date Access. După ce am setat un nume pentru baza de date urmează să încercăm să deschidem baza de date. Daca acest lucru nu a fost posibil vom afișa un mesaj de eroare prin care să semnalăm eroare întâmpinată.
Executarea unor interogări SQL
Clasa "QSqlQuery":http://doc.qt.nokia.com/4.7-snapshot/qsqlquery.html oferă o interfață pentru executarea unor interogări SQL și navigare prin setul de rezultate al interogării. Clasele "QSqlQueryModel ":http://doc.qt.nokia.com/4.7-snapshot/qsqlquerymodel.html și "QSqlTableModel ":http://doc.qt.nokia.com/4.7-snapshot/qsqltablemodel.html oferă un suport de un nivel mai înalt pentru accesarea unei baze de date.
Pentru a executa un query SQL putem crea un obiect de tip QSqlQuery iar mai apoi apelăm metoda "bool exec&#40;QString &query;)":http://doc.qt.nokia.com/4.7-snapshot/qsqlquery.html#exec precum în următorul exemplu :
QSqlQuery query(QSqlDatabase::database("MyDbConnectionName&quot;));<br /> query.exec&amp;#40;"SELECT ID FROM PROFILE ORDER BY ID ASC&quot;&#41;;
Constructorul obiectului QSqlQuery primește ca argument conexiunea la baza de date care va fi folosită. Dacă nu am fi specificat-o s-ar fi folosit conexiunea implicită.
QSqlQuery ne permite să accesăm rezultate doar pe rând. După ce executăm metoda exec&#40;), pointerul intern al lui QSqlQuery este localizat cu o poziție în urmă față de prima înregistrare. Pentru a avansa în setul de rezultate trebuie să apelăm metoda "bool next()":http://doc.qt.nokia.com/4.7-snapshot/qsqlquery.html#next. În exemplul următor se iterează peste rezultatele unei interogări :
while (query.next()) {<br /> id = query.value(0).toInt();<br /> if (id == free_id) {free_id++;<br /> } else {return free_id;}<br /> }
Funcția "QVariant value(int index) const":http://doc.qt.nokia.com/4.7-snapshot/qsqlquery.html#value returnează valoară câmpului cu indexul specificat din înregistrarea curentă. Numerotarea indexurilor câmpurilor începe de la zero. El returnează această valoare ca un "QVariant":http://doc.qt.nokia.com/4.7-snapshot/qvariant.html, un tip de date care poate păstra diverse tipuri precum int, QString sau QByteArray. În cazul din codul de mai sus folosim funcția "int toInt(bool* ok=0)const":http://doc.qt.nokia.com/4.7-snapshot/qvariant.html#toInt pentru a converti această valoare într-un int.
Dar putem itera atât înainte cât și înapoi folosind : "next()":http://doc.qt.nokia.com/4.7-snapshot/qsqlquery.html#next, "previous()":http://doc.qt.nokia.com/4.7-snapshot/qsqlquery.html#previous, "first()":http://doc.qt.nokia.com/4.7-snapshot/qsqlquery.html#first, "last()":http://doc.qt.nokia.com/4.7-snapshot/qsqlquery.html#last și "seek()":http://doc.qt.nokia.com/4.7-snapshot/qsqlquery.html#seek. Indexul înregistrării curente este returnat de funcția" int at() const":http://doc.qt.nokia.com/4.7-snapshot/qsqlquery.html#at, iar numărul total de înregistrări din setul de rezultate se obține apelând funcția "int size() const":http://doc.qt.nokia.com/4.7-snapshot/qsqlquery.html#size.
Pentru a deternina dacă un anumit driver posedă o anumită trăsătură apelăm funcția "bool QSqlDriver::hasFeature()":http://doc.qt.nokia.com/4.7-snapshot/qsqldriver.html#hasFeature. Dacă iterăm printr-un set de rezultate folosind doar next() și seek() este recomandat să folosim funcția "QSqlQuery::setForwardOnly(true)":http://doc.qt.nokia.com/4.7-snapshot/qsqlquery.html#setForwardOnly înainte de a apela exec&#40;). Aceasta este o optimizare simplă prin care mărim viteza unor interogări mai ales în cazul în care lucrăm cu seturi mari de rezultate.
QSqlQuery poate executa orice tip de interogare SQL, nu doar SELECTuri. Dacă dorim să inserăm mai multe valori deodată, este mai eficient să separăm interogarea de valorile ce urmează să le inserăm. Acest lucru poate fi făcut prin intermediul unor substituenți. Qt oferă suport pentru două tipuri de substituenți :
* substituenți cu nume și
* substituenți poziționali.
Un exemplu în care se folosesc substituenți cu nume poate fi văzut în următoarea secvență de cod :
QSqlQuery query(QSqlDatabase::database("MyDbConnectionName&quot;));<br /> query.prepare("INSERT INTO PROFILE&quot;<br /> " (Id,Name)"<br /> " VALUES (:Id,:Name)");<br /> query.bindValue(":Id&quot;, profile</s>>getId());<br /> query.bindValue(":Name&quot;, profile->getName());<br /> query.exec&amp;#40;&#41;;
Utilizarea unui model SQL
Pe lângă QSqlQuery, Qt oferă clase de nivel înalt pentru accesarea bazelor de date. Aceste clase sunt:
- "QSqlQueryModel":http://doc.qt.nokia.com/4.7-snapshot/qsqlquerymodel.html;
- "QSqlTableModel":http://doc.qt.nokia.com/4.7-snapshot/qsqltablemodel.html;
- "QSqlRelationalTableModel":http://doc.qt.nokia.com/4.7-snapshot/qsqlrelationaltablemodel.html.
Aceste clase ușurează prezentarea datelor dintr-o bază de date într-o vizualizare de prezentare a datelor precum "QListView":http://doc.qt.nokia.com/4.7-snapshot/qlistview.html sau "QTableView":http://doc.qt.nokia.com/4.7-snapshot/qtableview.html.
- "QSqlQueryModel":http://doc.qt.nokia.com/4.7-snapshot/qsqlquerymodel.html oferă un model care poate fi doar citit bazat pe o interogare SQL. Un exemplu de folosire îl aveți mai jos :
myModel = new QSqlQueryModel(this);<br /> myModel->setQuery("SELECT * FROM PROFILE&quot;,<br /> QSqlDatabase::database("MyDbConnectionName&quot;));
- "QSqlTableModel":http://doc.qt.nokia.com/4.7-snapshot/qsqltablemodel.html oferă un model editabil pentru un singur tabel dintr-o bază de date. Nu presupune cunostințe de sintaxă SQL. Tabelul se selectează prin apelul funcției "void setTable(const QString& tableName)":http://doc.qt.nokia.com/4.7-snapshot/qsqltablemodel.html#setTable. Mai apoi putem apela la filtre sau sorta după o anumită coloană precum în exemplul următor :
QSqlTableModel model;<br /> model.setTable("PROFILE&quot;);<br /> model.setFilter("Age > 50&quot;);<br /> model.setSort(2, Qt::DescendingOrder);<br /> model.select();
"QSqlRelationalTableModel":http://doc.qt.nokia.com/4.7-snapshot/qsqlrelationaltablemodel.html oferă suport pentru chei externe. O cheie externă este o relație de unu la unu între un câmp dintr-un tabel la cheia primară a unui alt tabel. De exemplu daca tabelul book are un câmp numit authorid care indifică câmpul id de al tabelului author, spunem că authorid este o cheie externă.