Vereinfachen Sie die Arbeit mit Datenbanken in Qt mit QSqlRelationalTableModel

Guten Tag, Chabrowsk! In diesem Artikel möchte ich über meine Erfahrungen mit der Vereinfachung der Interaktion mit SQL-Datenbanken bei der Entwicklung einer Desktopanwendung mithilfe der QSqlRelationalTableModel-Klasse der plattformübergreifenden Qt-Bibliothek sprechen.

Prolog


Ich habe Qt kennengelernt, als ich im ersten Jahr war und gerade angefangen habe, in C ++ zu programmieren. Gleichzeitig habe ich mich ernsthaft für die Bibliothek interessiert und verfolge seitdem deren Aktualisierungen. Vor einigen Monaten gaben sie mir bei der Arbeit eine TOR, in der es notwendig war, eine Anwendung zu entwickeln, die mit der SQLite-Datenbank interagiert. Die Struktur der Basis ist fest und mir von TK im Voraus bekannt.

Die Anwendung sollte es dem Bediener ermöglichen, die in der Datenbank gespeicherten Daten bequem darzustellen, neue Datensätze hinzuzufügen, vorhandene zu löschen und zu ändern.

Als nächstes werde ich den Entwicklungsprozess kurz mit Codefragmenten beschreiben und versuchen zu erklären, warum in diesem Fall die Wahl zugunsten von QSqlRelationalTableModel getroffen wurde .

Entwicklungsstart


Zunächst wurde beschlossen, eine Interaktion mit der Datenbank unter Verwendung einfacher Datenbankabfragen herzustellen, d. H. SELECT , INSERT , DELETE , mit denen Sie alle erforderlichen Funktionen der Anwendung implementieren können.

Dazu benötigen wir die Klassen QSqlDatabase und QSQlQuery :

QSqlDatabase db; //    db = QSqlDatabase::addDatabase("QSQLITE"); //    db.setHostName("localhost"); //  ,    db.setDatabaseName(path); //QString path -    //   if(db.open()){ qDebug() << "db opened OK..."; }else{ qDebug() << " db opening failed..."; } }else{ qDebug() << "file doesnot exist"; exit(0); // ,     , //   } 

Danach werden alle Vorgänge in der Datenbank wie folgt ausgeführt:

 // ,    <b>QLineEdit</b>' QString query = "INSERT INTO Table (column) VALUES ('" + ui->Input->text() + "')"; QSqlQuery sqlQuery(db); //c   qDebug() << "QUERY: " << query; // //   if(sqlQuery.exec(query)){ qDebug() << "query failed..."; } else{ qDebug() << "query failed..."; } 

Select-Anweisungen werden ähnlich ausgeführt, außer dass die Daten noch empfangen und irgendwo abgelegt werden müssen:

 QString query = "SELECT id, ka FROM Table"; QSqlQuery sqlQ(db); if(!sqlQ.exec(query)) { qDebug() << "query failed..."; return; } //     // ,        while (sqlQ.next()){ //           ui->ComboBox->addItem(sqlQ.value(1).toString(),sqlQ.value(0).toInt()); } 

Delete-Anweisungen werden genauso ausgeführt wie Insert, da sie nichts zurückgeben.

Alles klar, was ist das Problem?


Und die Wahrheit ist, Sie können alles durch diese Ausdrücke und Abfragen implementieren. Warum brauchen wir Modelle?

Wenn wir eine nicht verwandte Tabelle haben, scheint alles sehr einfach zu sein und erfordert keine Einführung zusätzlicher Tools. Stellen Sie sich nun vor, wir haben solche Tabellen, zum Beispiel 5 mit jeweils 5 Spalten, ohne ID. Und jeder hat eine Verbindung mit dem vorherigen unter Verwendung eines Fremdschlüssels über eine ID , d. H. Beim Löschen muss eine Kaskade erstellt werden, um alle "untergeordneten" Datensätze zu löschen. Dies führt zu einer großen Anzahl von Anforderungen, die Arbeit der Anwendung wird erheblich verlangsamt. Darüber hinaus müssen die Tabelle und ihre Darstellung jedes Mal in der Benutzeroberfläche aktualisiert werden. Dies führt dazu, dass zusätzliche Funktionen für die Aktualisierung, das Auftreten von Fehlern oder das Risiko ihres Auftretens geschrieben und im Allgemeinen die Lesbarkeit verringert werden Code.

Aus diesem Grund musste ich während des Entwicklungsprozesses das Konzept der Verwendung von Bare- SQL- Abfragen aufgeben.

Weitere Entscheidungen wurden zugunsten von QSqlRelationalTableModel in Verbindung mit QTableView getroffen . Es gibt eine noch einfachere Version der Modellimplementierung : QSqlTableModel , das erste wird von ihm geerbt, verfügt über dieselben Methoden, bietet jedoch die Möglichkeit, eine QSqlRelation- Verbindung zu erstellen. Dies ist sehr praktisch, wenn der Benutzer nicht die Datensatz-ID, sondern den Namen des Datensatzes "übergeordnet" anzeigen muss, mit dem es versehen ist verbunden.

Schauen wir uns die Implementierung mit Modellen an


Hier sind einige Pod-Auszüge, die die Implementierung von Modell / Ansicht zeigen.

In der Header-Datei:

 QSqlRelationalTableModel *model; 

Im Konstruktor:

 //  ,    //  QTableView  ,    //QModelIndex     ,      connect(ui->tableView, SIGNAL(clicked(const QModelIndex &)), this, SLOT(onTableClicked(const QModelIndex &))); model = new QSqlRelationalTableModel(parent, db); // , QSqlDatabase    model->setTable("Table"); //    

Die folgende Zeile enthält eine der bequemsten Funktionen und Vorteile des Modells gegenüber SQL-Abfragen: Je nach Kontext werden die Daten in der SQL-Tabelle beim Wechsel von zu QTableView bearbeitet, hinzugefügt und gelöscht. Der Vorteil ist, dass Sie nicht mehr die Richtigkeit des kaskadierenden Löschens und Aktualisierens von Daten in einer einzigen QTableView kontrollieren müssen.

 model->setEditStrategy(QSqlRelationalTableModel::OnFieldChange); 

Als nächstes kommt eine weitere praktische Funktion dieser Klasse: Es wird eine Verbindung zwischen zwei Spalten verschiedener Tabellen hergestellt:

 //ParentTable - ,      //id - ,         //name - ,        model->setRelation(1,QSqlRelation("ParentTable", "id", "name")); 

Außerdem ist alles Standard: select () führt eine SELECT-Anweisung aus und setHeaderData () setzt den Text in den QTableView-Headern:

 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); //     QTableView 

Jetzt arbeiten model und tableView zusammen und führen ihre Funktionen aus. Ein Link zu Github hinterlässt alle Quellen. In diesen habe ich einen Eintrag zum Modell hinzugefügt, ihn gelöscht sowie Filter.

Fazit


In diesem Artikel wollte ich alle, die bereits mit der Datenbank in Qt arbeiten, ermutigen, reine SQL-Abfragen für Projekte mit mindestens mittlerer Komplexität aufzugeben und auf die Arbeit mit Modellen umzusteigen, um ihr Leben zu vereinfachen, den Code lesbarer und universeller zu machen. Mach einfach etwas Gutes und Neues.

Das ist alles! Ich hoffe, dass meine Erfahrung mit diesen Kursen den Lesern hilft, ein ähnliches Problem erfolgreich zu lösen!

Source: https://habr.com/ru/post/de435134/


All Articles