Accueil | Téléchargement | Exemple rapide |
Tutoriel (4)
|
Manuel (2)
|
Forum | Nos clients |
QxOrm >> Tutoriel >> qxBlog |
|
Autre remarque : il existe un projet similaire dans le dossier './test/qxBlogCompositeKey/' pour montrer comment définir des identifiants sur plusieurs colonnes (composite key). Pour plus d'informations sur cette notion de 'multi-columns primary key' : suivre ce lien du manuel utilisateur. 1- Projet qxBlog - gestion d'un blog en C++ avec les tables suivantes :
2- Le projet qxBlog du tutoriel a l'arborescence suivante :
Remarque : le code source de ce tutoriel est disponible dans le dossier
./test/qxBlog/ de la distribution de QxOrm.
5- Contenu du fichier precompiled.h : Il s'agit d'un en-tête précompilé (precompiled header) permettant d'optimiser les temps de compilation du projet. En effet, QxOrm utilise les techniques de métaprogrammation pour fournir l'ensemble de ses fonctionnalités. La métaprogrammation étant couteuse en temps de compilation, un projet C++ se compilera beaucoup plus vite avec un fichier precompiled.h. Un seul fichier d'en-tête est nécessaire pour disposer de l'ensemble des fonctionnalités de QxOrm : le fichier QxOrm.h.
6- Contenu des fichiers author.h et author.cpp (relation one-to-many) : Un author est une personne qui peut rédiger plusieurs blog : nous allons ainsi montrer comment utiliser la relation de type one-to-many. Au niveau base de données, voici les deux tables qui correspondent : Dans le code C++, les propriétés de la classe author sont le symétrique des champs de la table author dans la base de données. Donc une instance de la classe author dans le code C++ correspond à une ligne de la table author dans la base de données. Ce principe permet d'écrire du code C++ simple de compréhension et facile à maintenir. Nous ajoutons une méthode à notre classe author : int age() qui calculera l'âge en fonction de la date de naissance envoyée par la base de données. Nous écrivons également deux typedef pour représenter un pointeur (smart-pointer) vers un objet author ainsi qu'une collection de author. La classe author a un identifiant de type QString (par défaut, un identifiant dans le contexte QxOrm est de type long) : nous utilisons la macro QX_REGISTER_PRIMARY_KEY(author, QString) pour spécialiser le template. La classe author s'écrit de la façon suivante :
7- Contenu des fichiers comment.h et comment.cpp (relation many-to-one) : Un comment est associé à un blog et un blog peut contenir plusieurs comment : nous allons ainsi montrer comment utiliser la relation de type many-to-one. Au niveau base de données, voici les deux tables qui correspondent (nous reprenons la table blog vue précédemment) : De même que pour la classe author, nous écrivons deux typedef pour représenter un pointeur vers un objet comment ainsi qu'une collection de comment. La classe comment s'écrit de la façon suivante :
8- Contenu des fichiers category.h et category.cpp (relation many-to-many) : Une category référence plusieurs blog et un blog peut appartenir à plusieurs category : nous allons ainsi montrer comment utiliser la relation de type many-to-many. Ce type de relation implique une table supplémentaire dans la base de données pour stocker la liste des id de chaque côté des relations. Au niveau base de données, voici les trois tables qui correspondent (nous reprenons la table blog vue précédemment) : De même que pour les classes author et comment, nous écrivons deux typedef pour représenter un pointeur vers un objet category ainsi qu'une collection de category. La classe category s'écrit de la façon suivante :
9- Contenu des fichiers blog.h et blog.cpp (relations one-to-many, many-to-one et many-to-many) : Un blog est écrit par un author, peut avoir plusieurs comment et peut être associé à plusieurs category. Cette classe contient donc trois relations : one-to-many, many-to-one et many-to-many. Remarque : QxOrm gère également le type de relation one-to-one qui est cependant beaucoup moins utilisée que les autres relations. Un exemple de type de relation one-to-one est disponible en annexe de ce tutoriel avec la classe/table person : une person correspond à un author. De même que pour les autres classes, nous écrivons deux typedef pour représenter un pointeur vers un objet blog ainsi qu'une collection de blog. La classe blog s'écrit de la façon suivante :
10- Contenu du fichier main.cpp : QxOrm permet de communiquer de manière simple et performante avec de nombreuses bases de données (voir la liste des bases de données supportées sur le site de Qt). Il est recommandé d'utiliser un pilote spécifique à la base de données afin d'optimiser les performances : le pilote QODBC, bien que générique et permettant de s'interfacer avec la plupart des bases de données du marché, sera moins performant qu'un pilote natif (par exemple, le pilote QMYSQL pour une base de données MySQL). Outre la persistance, QxOrm possède également d'autres fonctionnalités intéressantes liées à la gestion des données :
Voici les traces générées après exécution du programme qxBlog : [QxOrm] qx::QxSqlDatabase : create new database connection in thread '4456' with key '{e986c95d-1cb0-4368-ad9c-3dd4ccd20b84}' [QxOrm] sql query (93 ms) : DELETE FROM author [QxOrm] sql query (63 ms) : DELETE FROM comment [QxOrm] sql query (94 ms) : DELETE FROM category [QxOrm] sql query (78 ms) : DELETE FROM blog [QxOrm] sql query (62 ms) : INSERT INTO author (author_id, name, birthdate, sex) VALUES (:author_id, :name, :birthdate, :sex) [QxOrm] sql query (0 ms) : SELECT COUNT(*) FROM author [QxOrm] sql query (0 ms) : SELECT author.author_id AS author_author_id_0, author.name AS author_name_0, author.birthdate AS author_birthdate_0, author.sex AS author_sex_0 FROM author WHERE author.sex = :sex [QxOrm] start dump 'qx::QxCollection<QString, boost::shared_ptr<author>>' <qx.QxCollection-QString_boost.shared_ptr-author-- class_id="0" tracking_level="0" version="0"> <count>2</count> <item class_id="1" tracking_level="0" version="0"> <first class_id="2" tracking_level="0" version="0">author_id_2</first> <second class_id="3" tracking_level="0" version="1"> <px class_id="4" tracking_level="1" version="0" object_id="_0"> <author_id>author_id_2</author_id> <name>author_2</name> <birthdate class_id="5" tracking_level="0" version="0">20100409</birthdate> <sex>1</sex> <list_blog class_id="6" tracking_level="0" version="0"> <count>0</count> <item_version>1</item_version> </list_blog> </px> </second> </item> <item> <first>author_id_3</first> <second> <px class_id_reference="4" object_id="_1"> <author_id>author_id_3</author_id> <name>author_3</name> <birthdate>20100409</birthdate> <sex>1</sex> <list_blog> <count>0</count> <item_version>1</item_version> </list_blog> </px> </second> </item> </qx.QxCollection-QString_boost.shared_ptr-author--> [QxOrm] end dump 'qx::QxCollection<QString, boost::shared_ptr<author>>' [QxOrm] sql query (0 ms) : INSERT INTO category (name, description) VALUES (:name, :description) [QxOrm] sql query (0 ms) : INSERT INTO category (name, description) VALUES (:name, :description) [QxOrm] sql query (0 ms) : INSERT INTO category (name, description) VALUES (:name, :description) [QxOrm] sql query (0 ms) : INSERT INTO blog (blog_text, date_creation, author_id) VALUES (:blog_text, :date_creation, :author_id) [QxOrm] sql query (0 ms) : SELECT blog.blog_id AS blog_blog_id_0 FROM blog WHERE blog_blog_id_0 = :blog_id [QxOrm] sql query (0 ms) : UPDATE blog SET blog_id = :blog_id, blog_text = :blog_text, date_creation = :date_creation, author_id = :author_id WHERE blog_id = :blog_id_bis [QxOrm] sql query (78 ms) : INSERT INTO comment (comment_text, date_creation, blog_id) VALUES (:comment_text, :date_creation, :blog_id) [QxOrm] sql query (78 ms) : INSERT INTO comment (comment_text, date_creation, blog_id) VALUES (:comment_text, :date_creation, :blog_id) [QxOrm] sql query (0 ms) : SELECT COUNT(*) FROM comment [QxOrm] sql query (0 ms) : SELECT blog.blog_id AS blog_blog_id_0 FROM blog WHERE blog_blog_id_0 = :blog_id [QxOrm] sql query (0 ms) : UPDATE blog SET blog_id = :blog_id, blog_text = :blog_text, date_creation = :date_creation, author_id = :author_id WHERE blog_id = :blog_id_bis [QxOrm] sql query (0 ms) : SELECT category.category_id AS category_category_id_0 FROM category WHERE category_category_id_0 = :category_id [QxOrm] sql query (0 ms) : UPDATE category SET category_id = :category_id, name = :name, description = :description WHERE category_id = :category_id_bis [QxOrm] sql query (0 ms) : SELECT category.category_id AS category_category_id_0 FROM category WHERE category_category_id_0 = :category_id [QxOrm] sql query (0 ms) : UPDATE category SET category_id = :category_id, name = :name, description = :description WHERE category_id = :category_id_bis [QxOrm] sql query (extra-table) : DELETE FROM category_blog WHERE category_blog.blog_id = :blog_id [QxOrm] sql query (extra-table) : INSERT INTO category_blog (blog_id, category_id) VALUES (:blog_id, :category_id) [QxOrm] sql query (0 ms) : SELECT blog.blog_id AS blog_blog_id_0, blog.blog_text AS blog_blog_text_0, blog.date_creation AS blog_date_creation_0, blog.author_id AS blog_author_id_0, author_1.author_id AS author_1_author_id_0, author_1.name AS author_1_name_0, author_1.birthdate AS author_1_birthdate_0, author_1.sex AS author_1_sex_0, comment_2.comment_id AS comment_2_comment_id_0, comment_2.blog_id AS comment_2_blog_id_0, comment_2.comment_text AS comment_2_comment_text_0, comment_2.date_creation AS comment_2_date_creation_0, category_3.category_id AS category_3_category_id_0, category_3.name AS category_3_name_0, category_3.description AS category_3_description_0 FROM blog LEFT OUTER JOIN author author_1 ON author_1_author_id_0 = blog_author_id_0 LEFT OUTER JOIN comment comment_2 ON comment_2_blog_id_0 = blog_blog_id_0 LEFT OUTER JOIN category_blog ON blog_blog_id_0 = category_blog.blog_id LEFT OUTER JOIN category category_3 ON category_blog.category_id = category_3_category_id_0 WHERE blog_blog_id_0 = :blog_id [QxOrm] start dump 'boost::shared_ptr<blog>' <boost.shared_ptr-blog- class_id="0" tracking_level="0" version="1"> <px class_id="1" tracking_level="1" version="0" object_id="_0"> <blog_id>113</blog_id> <blog_text class_id="2" tracking_level="0" version="0">update blog_text_1</blog_text> <date_creation class_id="3" tracking_level="0" version="0">20100409162612000</date_creation> <author_id class_id="4" tracking_level="0" version="1"> <px class_id="5" tracking_level="1" version="0" object_id="_1"> <author_id>author_id_2</author_id> <name>author_2</name> <birthdate class_id="6" tracking_level="0" version="0">20100409</birthdate> <sex>1</sex> <list_blog class_id="7" tracking_level="0" version="0"> <count>0</count> <item_version>1</item_version> </list_blog> </px> </author_id> <list_comment class_id="8" tracking_level="0" version="0"> <count>2</count> <item class_id="9" tracking_level="0" version="1"> <px class_id="10" tracking_level="1" version="0" object_id="_2"> <comment_id>209</comment_id> <comment_text>comment_1 text</comment_text> <date_creation>20100409162612000</date_creation> <blog_id> <px class_id_reference="1" object_id="_3"> <blog_id>113</blog_id> <blog_text></blog_text> <date_creation></date_creation> <author_id> <px class_id="-1"></px> </author_id> <list_comment> <count>0</count> </list_comment> <list_category class_id="11" tracking_level="0" version="0"> <count>0</count> </list_category> </px> </blog_id> </px> </item> <item> <px class_id_reference="10" object_id="_4"> <comment_id>210</comment_id> <comment_text>comment_2 text</comment_text> <date_creation>20100409162612000</date_creation> <blog_id> <px class_id_reference="1" object_id="_5"> <blog_id>113</blog_id> <blog_text></blog_text> <date_creation></date_creation> <author_id> <px class_id="-1"></px> </author_id> <list_comment> <count>0</count> </list_comment> <list_category> <count>0</count> </list_category> </px> </blog_id> </px> </item> </list_comment> <list_category> <count>2</count> <item class_id="12" tracking_level="0" version="0"> <first>355</first> <second class_id="13" tracking_level="0" version="0"> <qt_shared_ptr class_id="14" tracking_level="1" version="0" object_id="_6"> <category_id>355</category_id> <name>category_1</name> <description>desc_1</description> <list_blog class_id="15" tracking_level="0" version="0"> <count>0</count> </list_blog> </qt_shared_ptr> </second> </item> <item> <first>357</first> <second> <qt_shared_ptr class_id_reference="14" object_id="_7"> <category_id>357</category_id> <name>category_3</name> <description>desc_3</description> <list_blog> <count>0</count> </list_blog> </qt_shared_ptr> </second> </item> </list_category> </px> </boost.shared_ptr-blog-> [QxOrm] end dump 'boost::shared_ptr<blog>' Remarque importante : QxOrm n'a pas pour objectif de 'cacher' le code SQL (par défaut toutes les requêtes sont tracées). Même si QxOrm simplifie énormément le code C++ et optimise ainsi les temps de développement et de maintenance d'un produit, il est très important d'avoir de bonnes connaissances SQL. QxOrm ne résoudra pas toutes les problématiques liées aux bases de données (par exemple, jointure limitée à deux tables dans une même requête), il sera alors nécessaire d'utiliser directement le module QtSql de Qt en écrivant soi-même les requêtes SQL ou les procédures stockées. Enfin, il faut être extrêmement vigilant au nombre de requêtes effectuées entre le programme C++ et la base de données : un trop grand nombre d'appels à la base de données peut détériorer les performances d'une application. Il est important de maîtriser la notion de relations entre les classes ou bien de jointures pour les tables d'une base de données (voir le syndrome n+1 SELECT que l'on peut rencontrer avec Hibernate ou tout autre ORM). Pour plus d'informations sur le langage SQL, regardez l'excellent site de Frédéric Brouart. Autre remarque : il est important de signaler que les méthodes void register_class(...) sont appelées automatiquement et lorsque c'est nécessaire par la bibliothèque QxOrm. Par rapport à d'autres bibliothèques qui nécessitent un appel pour enregistrer les types de chaque classe, QxOrm permet un enregistrement automatique des classes, ce qui simplifie encore un peu plus le développement d'applications. 11- Annexe - exemple de relation one-to-one avec la classe person : Ajoutons à notre projet la classe person (fichiers person.h et person.cpp) : une person correspond à un author dans la base de données. Ils partagent donc le même identifiant, c'est ce qu'on appelle une relation de type one-to-one. Voici les deux tables de notre base de données (nous reprenons la table author vue précédemment) : Remarque : nous ajoutons à la table person le champ mother_id. Nous pouvons ainsi connaître la mère (de type person) associée à une person, ce qui correspond à une relation many-to-one sur la même table person. De plus, si une person est une mère, nous pouvons connaître la liste de ses enfants (de type person), ce qui correspond à une relation one-to-many sur la même table person. 12- Remerciements Je remercie tout particulièrement Thibaut Cuvelier pour ses conseils pour l'amélioration de ce tutoriel. Je remercie également Claude Leloup pour ses relectures et corrections orthographiques. |
© 2011-2024 Lionel Marty - contact@qxorm.com |