Bonjour, Khabrovsk! Dans cet article, je veux parler de mon expérience de la simplification de l'interaction avec les bases de données SQL lors du développement d'une application de bureau à l'aide de la classe QSqlRelationalTableModel de la bibliothèque multiplateforme Qt.
Prologue
J'ai rencontré Qt quand j'étais étudiant en première année, commençant tout juste à programmer en C ++, en même temps je me suis sérieusement intéressé à la bibliothèque et, depuis, je suis ses mises à jour. Il y a quelques mois, au travail, ils m'ont donné un TOR dans lequel il fallait développer une application qui interagit avec la base de données SQLite. La structure de la base est fixe et connue d'avance de TK.
L'application devrait être en mesure de fournir à l'opérateur les données stockées dans la base de données, de permettre l'ajout de nouveaux enregistrements, la suppression et la modification des enregistrements existants.
Ensuite, je vais décrire brièvement le processus de développement avec des extraits de code et essayer d'expliquer raisonnablement pourquoi, dans ce cas, le choix a été fait en faveur de
QSqlRelationalTableModel .
Début du développement
Initialement, il a été décidé d'établir une interaction avec la base de données à l'aide de simples requêtes de base de données, c'est-à-dire
SELECT ,
INSERT ,
DELETE , qui vous permettent d'implémenter toutes les fonctions nécessaires de l'application.
Pour ce faire, nous avons besoin des
classes QSqlDatabase et
QSQlQuery :
QSqlDatabase db;
Après cela, toutes les opérations sur la base de données sont effectuées comme suit:
Les instructions Select sont exécutées de la même manière, sauf que les données doivent encore être reçues et placées quelque part:
QString query = "SELECT id, ka FROM Table"; QSqlQuery sqlQ(db); if(!sqlQ.exec(query)) { qDebug() << "query failed..."; return; }
Les instructions de suppression sont exécutées exactement de la même manière que Insert car elles ne renvoient rien.
D'accord, quel est le problème?
Et la vérité est que vous pouvez tout implémenter à travers ces expressions et requêtes,
pourquoi avons-nous besoin de modèles?Lorsque nous avons une table indépendante, tout semble très simple et ne nécessite pas l'introduction d'outils supplémentaires. Imaginez maintenant que nous ayons de telles tables, par exemple 5, chacune avec 5 colonnes, sans inclure id. Et chacun a une connexion avec le précédent en utilisant
une clé étrangère via
id , c'est-à-dire lors de la suppression, il est nécessaire de cascader pour supprimer tous les enregistrements "enfants". Cela conduit à un grand nombre de requêtes, le travail de l'application ralentit considérablement, de plus, il est nécessaire de mettre à jour la table et sa présentation dans l'interface à chaque fois, ce qui conduit à écrire des fonctions supplémentaires pour la mise à jour, l'apparition de bugs ou au risque de leur occurrence, et en général pour réduire la lisibilité code.
Pour cette raison, au cours du processus de développement, j'ai dû abandonner le concept d'utilisation de requêtes
SQL nues.
D'autres choix ont été faits en faveur de
QSqlRelationalTableModel en conjonction avec
QTableView . Il existe une version encore plus simple de l'implémentation du modèle -
QSqlTableModel , la première en est héritée, elle a toutes les mêmes méthodes, mais ajoute la possibilité de créer une connexion
QSqlRelation , ce qui est très pratique si l'utilisateur doit afficher non pas l'ID d'enregistrement, mais le nom de l'enregistrement «parent» avec lequel il connecté.
Regardons l'implémentation avec des modèles
Voici quelques extraits de pods montrant l'implémentation du modèle / vue.
Dans le fichier d'en-tête:
QSqlRelationalTableModel *model;
Dans le constructeur:
La ligne ci-dessous contient l'une des fonctionnalités et des avantages les plus pratiques du modèle par rapport aux requêtes SQL - il modifie, ajoute, supprime, selon le contexte, les données de la table SQL lors du passage de à QTableView. La commodité est que vous n'avez plus besoin de contrôler l'exactitude de la suppression des données en cascade et de les mettre à jour dans un seul QTableView.
model->setEditStrategy(QSqlRelationalTableModel::OnFieldChange);
Vient ensuite une autre fonctionnalité pratique fournie par cette classe: une connexion est établie entre deux colonnes de tables différentes:
En outre, tout est plus standard: select () exécutera une instruction SELECT et setHeaderData () définira le texte dans les en-têtes QTableView:
model->select(); model->setHeaderData(0, Qt::Horizontal, tr("id")); model->setHeaderData(1, Qt::Horizontal, tr("id_sub")); model->setHeaderData(2, Qt::Horizontal, tr("count")); model->setHeaderData(3, Qt::Horizontal, tr("number")); model->setHeaderData(4, Qt::Horizontal, tr("data_word")); model->setHeaderData(5, Qt::Horizontal, tr("time")); model->setHeaderData(6, Qt::Horizontal, tr("name")); model->setHeaderData(7, Qt::Horizontal, tr("description")); ui->tableView->setModel(model);
Maintenant, le modèle et tableView fonctionnent ensemble et remplissent leurs fonctions. Un lien vers
github laissera toutes les sources, j'y ai implémenté l'ajout d'une entrée au modèle, sa suppression, ainsi que des filtres.
Conclusion
Dans cet article, je voulais encourager tous ceux qui travaillent déjà avec la base de données dans Qt à abandonner les requêtes SQL nues pour des projets de complexité au moins moyenne et à passer au travail avec des modèles afin de simplifier leur vie, rendre le code plus lisible et universel, eh bien, faites quelque chose de bien et de nouveau.
C’est tout! J'espère que mon expérience avec ces cours aidera les lecteurs à résoudre avec succès un problème similaire!