![]() |
|
|
![]() |
| 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-202XDL Teamty - ic-east.com |