Ich portiere eine mittelgroße CRUD-Anwendung von .NET nach Qt und suche nach einem Muster zum Erstellen von Persistenzklassen. In .NET habe ich normalerweise eine abstrakte Persistenzklasse mit grundlegenden Methoden (Einfügen, Aktualisieren, Löschen, Auswählen) erstellt, zum Beispiel:
%Vor%Dann habe ich eine Unterklasse für bestimmte Tabellen / DTOs erstellt und Attribute für das DB-Tabellenlayout hinzugefügt:
%Vor%Dank des .Net-Reflexionssystems konnte ich eine hohe Codewiederverwendung und die einfache Erstellung neuer ORMs erreichen.
Der einfachste Weg, um solche Sachen in Qt zu machen, scheint Modellklassen aus dem QtSql-Modul zu verwenden. Leider bieten sie in meinem Fall eine zu abstrakte Schnittstelle. Ich benötige zumindest Transaktionsunterstützung und Kontrolle über einzelne Commits, die QSqlTableModel nicht bereitstellt.
Könnten Sie mir ein paar Hinweise zur Lösung dieses Problems mit Qt geben oder auf Referenzmaterialien verweisen?
Aktualisierung:
Basierend auf Haralds Hinweisen habe ich eine Lösung implementiert, die den obigen .Net-Klassen ziemlich ähnlich ist. Jetzt habe ich zwei Klassen.
UniversalDAO , das QObject erbt und mit QObject DTOs arbeitet, die das metatype-System verwenden:
%Vor%Und ein generischer SpecializedDAO , der die von UniversalDAO erhaltenen Daten in den entsprechenden Typ umwandelt:
%Vor%Mit dem oben genannten erkläre ich die konkrete DAO-Klasse wie folgt:
%Vor%Von innerhalb ClientDAO muss ich einige Datenbankinformationen für UniversalDAO festlegen. Dort wird meine Implementierung hässlich, weil ich es so mache:
%Vor%Ich mache es im Konstruktor, so dass es auf den ersten Blick nicht sichtbar ist, wenn jemand durch die Kopfzeile blättert. In der .Net-Version war es einfach zu erkennen und zu erkennen.
Hast du ein paar Ideen, wie ich es besser machen könnte?
Soweit ich weiß, gibt es nichts fertig gemacht, das diese Einrichtung direkt in qt gibt. Es gibt einige mögliche Ansätze.
Implementieren Sie die Felder als Q_PROPERTY, die dann durch das Metaclass-System reflektiert werden und verwendet werden können, um generische DAO-Funktionalität zu implementieren
Sie können immer noch das QSqlTableModel verwenden, aber Schreibvorgänge mit Transaktionen kapseln. Wenn eine Transaktion fehlschlägt, aktualisieren Sie das Modell von der DB. Die Durchführbarkeit hängt von der Größe der Daten ab, die Sie im Modell gespeichert haben.
Wir verwenden derzeit einen auf TableModel / QSqlRecord basierenden Ansatz zum Lesen und Schreiben, in unserem System gibt es kein ORM-Mapping. Ich habe versucht, einen allgemeineren Ansatz zu entwickeln, aber die Refactoring-Arbeit, die wir tun müssten, um dorthin zu gelangen, ist im Moment zu teuer.
Dieser Link Ссылка ist nicht mit Qt verwandt, aber a guter Überblick über die Implementierungsmuster
Wenn Sie ein ORM wollen, das nur von Qt abhängt und auf Qt's Meta-Object System aufbaut, um eine Introspektion zu ermöglichen, sollten Sie ausprobieren QDjango . Zusätzlich zu den grundlegenden Erstellungs- / Aktualisierungs- / Löschoperationen auf Modellebene stellt es eine Abfrage-Set-Template-Klasse zur Verfügung (nach Djangos Abfragesätzen modelliert), die es ermöglicht, recht komplexe Suchvorgänge zu erstellen. Die QtScript-Integration ist ebenfalls im Gange.
Tegesoft hat kürzlich eine neue Version seiner Bibliothek mit dem Namen CAMP veröffentlicht, die C ++ - Laufzeitreflexion bietet, wie Sie sie verwenden. Netz. Ich denke, dies wird Ihnen ermöglichen, Ihre Anwendung wie in .Net zu erreichen.
Es gibt auch eine neue Open-Source-ORM-C ++ - Bibliothek: QxOrm . QxOrm basiert auf dem Modul QtSql Qt für die Kommunikation mit der Datenbank und boost :: serialization für die Serialisierung Ihrer Daten im XML- und Binärformat. Die Website ist in Französisch, aber ein kurzer Beispielcode und Tutorial-Code ist in Englisch (eine Übersetzung ist in Arbeit ...).
... Und noch ein neues Qt ORM: QST: QsT SQL Tools (letzte stabile Version - 0.4.2a Release ). QST stellt Mechanismen bereit, um einfache SQL-Abfragen zu generieren: SELECT, INSERT, DELETE, UNPDATE und EXECUTE. Version 0.4 verwendet T-SQL; Neue Version - 0.5 - wird PostgreSQL standardmäßig verwenden. Sie finden, dieses ORM basiert auf ursprünglichen, ungewöhnlichen Konzeptionen. Zum Beispiel wurde es in das Qt-Interview-System integriert, so dass Sie die Ansichtsdarstellung (Spaltenbreiten, Titel) sehr einfach einrichten können.
Es gibt Beispielprojekte für die Versionen 0.3 und 0.4: TradeDB 0.3, TradeDB 0.4. TradeDB 0.4 sollte nützlich sein, um QST zu lernen.
Das scheint eine ausgezeichnete Technik zu sein. Ich habe jedoch einige Probleme, meinen Prototyp zu bekommen, um n Verbindung zu kompilieren ....
Ich habe die Grundlagen bei der Beschreibung implementiert und rufe die DAO-Klasse auf, um eine Instanz eines meiner DB-residenten Objekte abzurufen.
Hier sind die Anweisungen, die diese Modellklassen aufrufen:
%Vor%In meiner AddressDAO.cpp habe ich:
%Vor%Bei der Linkzeit bekomme ich Folgendes:
%Vor% Wie würde ich die Methoden in der Klasse SpecializedDAO
richtig implementieren?
Aktualisierung:
Dumm mich, blöd mich, blöd mich ... ich habe das meistens zur Arbeit gebracht. Die Probleme ....
Meine Modellklassen (DTOs) sind in Namespaces eingebettet, und ich benutze Makros, um diese Namespaces zu definieren und zu verwenden. Außerdem habe ich versucht, eine gute Hierarchie für diese Klassen zu verwenden und festgestellt, dass moc
ein neues Problem mit Klassenhierarchien hat, die in Namespaces eingebettet sind ....
Ich glaube, dass Funktionsdefinitionen von Template-Klassen in der Header-Datei sein müssen - sie können nicht in separaten Kompilierungseinheiten sein.
qmake
beschäftigt sich nicht sehr gut mit Abhängigkeiten (Header-Dateien) beim Überschreiten von Bibliotheksgrenzen. Ich habe meine Model-Sachen in einer gemeinsamen Bibliothek und die 'main ()' Funktion (in einem separaten Verzeichnis) versuchte einen Datensatz aus der Datenbank zu lesen. Die 'main ()' C-Datei wurde nicht neu kompiliert, als ich meine Modellklassen-Headerdatei änderte ...
Hier sind weitere Details:
In SpecializedDAO.h:
%Vor%In UniversalDAO.cpp:
%Vor% Ein derzeit noch ausstehendes Problem ist die Verwendung benutzerdefinierter Typen für Eigenschaftstypen in meinen DTO-Klassen. Ich versuche, std::string
vs. QString
zu verwenden, aber egal was ich probiert habe (Q_DECLARE_METATYPE(std::string)
, qRegisterMetaType<std::string>()
, usw. schien nichts zu funktionieren .... musste auf Qt-basierte Typen zurückgreifen. Schade ....