Accueil | T�l�chargement | Exemple rapide | Tutoriel (4) | Manuel (2) | Forum | Nos clients

QxOrm >> Tutoriel >> qxBlog

Version courante : | QxOrm 1.5.0 - documentation en ligne de la biblioth�que QxOrm - GitHub
| QxEntityEditor 1.2.8

S�lection du tutoriel : | Tuto n�1 : qxBlog Tuto n�2 : qxClientServer Tuto n�3 : install QxOrm Tuto n�4 : video QxEntityEditor

Dans ce chapitre, nous allons traiter plusieurs fonctionnalit�s de la biblioth�que QxOrm avec la cr�ation d'un projet de gestion d'un blog en C++.
Le tutoriel qxBlog est constitu� des �tapes suivantes :

- 1- Projet qxBlog - gestion d'un blog en C++
- 2- Arborescence du projet qxBlog
- 3- Contenu du fichier qxBlog.pro
- 4- Contenu du fichier export.h
- 5- Contenu du fichier precompiled.h
- 6- Contenu des fichiers author.h et author.cpp (relation one-to-many)
- 7- Contenu des fichiers comment.h et comment.cpp (relation many-to-one)
- 8- Contenu des fichiers category.h et category.cpp (relation many-to-many)
- 9- Contenu des fichiers blog.h et blog.cpp (relations one-to-many, many-to-one et many-to-many)
- 10- Contenu du fichier main.cpp
- 11- Annexe - exemple de relation one-to-one avec la classe person
- 12- Remerciements

QxOrm library has been accepted into the Qt Ambassador Program

Remarque : ce tutoriel est �galement disponible sur le site www.developpez.com.
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 :

- blog : un blog est �crit par un author, peut avoir plusieurs comment et peut �tre associ� � plusieurs category ;
- author : un author peut r�diger plusieurs blog ;
- comment : un comment est associ� � un blog ;
- category : une category r�f�rence plusieurs blog.

2- Le projet qxBlog du tutoriel a l'arborescence suivante :

./qxBlog/ ./qxBlog/qxBlog.pro ./qxBlog/qxBlog.sqlite | ./qxBlog/include/precompiled.h ./qxBlog/include/export.h ./qxBlog/include/author.h ./qxBlog/include/blog.h ./qxBlog/include/category.h ./qxBlog/include/comment.h | ./qxBlog/src/author.cpp ./qxBlog/src/blog.cpp ./qxBlog/src/category.cpp ./qxBlog/src/comment.cpp ./qxBlog/src/main.cpp

Remarque : le code source de ce tutoriel est disponible dans le dossier ./test/qxBlog/ de la distribution de QxOrm.
Le fichier qxBlog.sqlite correspond � la base de donn�es du tutoriel au format SQLite.

3- Contenu du fichier qxBlog.pro :
Ce fichier permet la compilation du projet par l'outil qmake fourni par le framework Qt.
L'outil qmake est multiplateforme, ce qui signifie que le projet qxBlog peut �tre compil� sous Windows, Linux, Mac, etc.
Le fichier qxBlog.pro d�crit la liste de tous les fichiers du projet (header + source) ainsi que les d�pendances du projet.
Le projet qxBlog est d�pendant de la biblioth�que QxOrm qui est elle-m�me d�pendante des excellents frameworks boost et Qt.
Pour simplifier la gestion des d�pendances du projet, il est possible d'inclure le fichier QxOrm.pri.
Une information importante � renseigner dans le fichier qxBlog.pro est la d�finition d'une variable indiquant que l'on est en train de compiler le projet (voir le fichier export.h). En effet, tout comme le m�canisme des DLL sous Windows, la biblioth�que QxOrm a besoin de cette information pour exporter ou importer certaines classes. Pour notre projet, cette variable se nomme _BUILDING_QX_BLOG.

4- Contenu du fichier export.h :
L'�criture d'une DLL sous Windows impose d'avoir un fichier de ce type pour la gestion des 'export/import' des classes, fonctions, variables, etc.
QxOrm utilise ce m�me m�canisme pour fournir certaines fonctionnalit�s : le fichier export.h est donc indispensable pour tous les projets qui d�pendent de QxOrm.
Remarque : pour simplifier, il est possible de sch�matiser le m�canisme des DLL de la fa�on suivante :

- lorsque la DLL est compil�e, l'outil de compilation exporte chaque classe ;
- lorsqu'une autre DLL d�pendante de la pr�c�dente est compil�e, l'outil de compilation importe les classes n�cessaires de la DLL pr�c�dente.

    #ifndef _QX_BLOG_EXPORT_H_
    #define _QX_BLOG_EXPORT_H_

    #ifdef _BUILDING_QX_BLOG
    #define QX_BLOG_DLL_EXPORT QX_DLL_EXPORT_HELPER
    #else // _BUILDING_QX_BLOG
    #define QX_BLOG_DLL_EXPORT QX_DLL_IMPORT_HELPER
    #endif // _BUILDING_QX_BLOG

    #ifdef _BUILDING_QX_BLOG
    #define QX_REGISTER_HPP_QX_BLOG QX_REGISTER_HPP_EXPORT_DLL
    #define QX_REGISTER_CPP_QX_BLOG QX_REGISTER_CPP_EXPORT_DLL
    #else // _BUILDING_QX_BLOG
    #define QX_REGISTER_HPP_QX_BLOG QX_REGISTER_HPP_IMPORT_DLL
    #define QX_REGISTER_CPP_QX_BLOG QX_REGISTER_CPP_IMPORT_DLL
    #endif // _BUILDING_QX_BLOG

    #endif // _QX_BLOG_EXPORT_H_

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.

    #ifndef _QX_BLOG_PRECOMPILED_HEADER_H_
    #define _QX_BLOG_PRECOMPILED_HEADER_H_

    #include <QxOrm.h>

    #include "export.h"

    #endif // _QX_BLOG_PRECOMPILED_HEADER_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 :

    #ifndef _QX_BLOG_AUTHOR_H_
    #define _QX_BLOG_AUTHOR_H_

    class blog;

    class QX_BLOG_DLL_EXPORT author
    {
    public:
    // -- typedef
       typedef boost::shared_ptr<blog> blog_ptr;
       typedef std::vector<blog_ptr> list_blog;
    // -- enum
       enum enum_sex { male, female, unknown };
    // -- propri�t�s
       QString     m_id;
       QString     m_name;
       QDate       m_birthdate;
       enum_sex    m_sex;
       list_blog   m_blogX;
    // -- constructeur, destructeur virtuel
       author() : m_id(0), m_sex(unknown) { ; }
       virtual ~author() { ; }
    // -- m�thodes
       int age() const;
    };

    QX_REGISTER_PRIMARY_KEY(author, QString)
    QX_REGISTER_HPP_QX_BLOG(author, qx::trait::no_base_class_defined, 0)

    typedef boost::shared_ptr<author> author_ptr;
    typedef qx::QxCollection<QString, author_ptr> list_author;

    #endif // _QX_BLOG_AUTHOR_H_

    #include "../include/precompiled.h"

    #include "../include/author.h"
    #include "../include/blog.h"

    #include <QxOrm_Impl.h>

    QX_REGISTER_CPP_QX_BLOG(author)

    namespace qx {
    template <> void register_class(QxClass<author> & t)
    {
       t.id(& author::m_id, "author_id");

       t.data(& author::m_name, "name");
       t.data(& author::m_birthdate, "birthdate");
       t.data(& author::m_sex, "sex");

       t.relationOneToMany(& author::m_blogX, "list_blog", "author_id");

       t.fct_0<int>(& author::age, "age");
    }}

    int author::age() const
    {
       if (! m_birthdate.isValid()) { return -1; }
       return (QDate::currentDate().year() - m_birthdate.year());
    }

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 :

    #ifndef _QX_BLOG_COMMENT_H_
    #define _QX_BLOG_COMMENT_H_

    class blog;

    class QX_BLOG_DLL_EXPORT comment
    {
    public:
    // -- typedef
       typedef boost::shared_ptr<blog> blog_ptr;
    // -- propri�t�s
       long        m_id;
       QString     m_text;
       QDateTime   m_dt_create;
       blog_ptr    m_blog;
    // -- constructeur, destructeur virtuel
       comment() : m_id(0) { ; }
       virtual ~comment() { ; }
    };

    QX_REGISTER_HPP_QX_BLOG(comment, qx::trait::no_base_class_defined, 0)

    typedef boost::shared_ptr<comment> comment_ptr;
    typedef QList<comment_ptr> list_comment;

    #endif // _QX_BLOG_COMMENT_H_

    #include "../include/precompiled.h"

    #include "../include/comment.h"
    #include "../include/blog.h"

    #include <QxOrm_Impl.h>

    QX_REGISTER_CPP_QX_BLOG(comment)

    namespace qx {
    template <> void register_class(QxClass<comment> & t)
    {
       t.id(& comment::m_id, "comment_id");

       t.data(& comment::m_text, "comment_text");
       t.data(& comment::m_dt_create, "date_creation");

       t.relationManyToOne(& comment::m_blog, "blog_id");
    }}

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 :

    #ifndef _QX_BLOG_CATEGORY_H_
    #define _QX_BLOG_CATEGORY_H_

    class blog;

    class QX_BLOG_DLL_EXPORT category
    {
    public:
    // -- typedef
       typedef boost::shared_ptr<blog> blog_ptr;
       typedef qx::QxCollection<long, blog_ptr> list_blog;
    // -- propri�t�s
       long        m_id;
       QString     m_name;
       QString     m_desc;
       list_blog   m_blogX;
    // -- constructeur, destructeur virtuel
       category() : m_id(0) { ; }
       virtual ~category() { ; }
    };

    QX_REGISTER_HPP_QX_BLOG(category, qx::trait::no_base_class_defined, 0)

    typedef QSharedPointer<category> category_ptr;
    typedef qx::QxCollection<long, category_ptr> list_category;

    #endif // _QX_BLOG_CATEGORY_H_

    #include "../include/precompiled.h"

    #include "../include/category.h"
    #include "../include/blog.h"

    #include <QxOrm_Impl.h>

    QX_REGISTER_CPP_QX_BLOG(category)

    namespace qx {
    template <> void register_class(QxClass<category> & t)
    {
       t.id(& category::m_id, "category_id");

       t.data(& category::m_name, "name");
       t.data(& category::m_desc, "description");

       t.relationManyToMany(& category::m_blogX, "list_blog", "category_blog", "category_id", "blog_id");
    }}

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 :

    #ifndef _QX_BLOG_BLOG_H_
    #define _QX_BLOG_BLOG_H_

    #include "author.h"
    #include "comment.h"
    #include "category.h"

    class QX_BLOG_DLL_EXPORT blog
    {
    public:
    // -- propri�t�s
       long           m_id;
       QString        m_text;
       QDateTime      m_dt_creation;
       author_ptr     m_author;
       list_comment   m_commentX;
       list_category  m_categoryX;
    // -- constructeur, destructeur virtuel
       blog() : m_id(0) { ; }
       virtual ~blog() { ; }
    };

    QX_REGISTER_HPP_QX_BLOG(blog, qx::trait::no_base_class_defined, 0)

    typedef boost::shared_ptr<blog> blog_ptr;
    typedef std::vector<blog_ptr> list_blog;

    #endif // _QX_BLOG_BLOG_H_

    #include "../include/precompiled.h"

    #include "../include/blog.h"

    #include <QxOrm_Impl.h>

    QX_REGISTER_CPP_QX_BLOG(blog)

    namespace qx {
    template <> void register_class(QxClass<blog> & t)
    {
       t.id(& blog::m_id, "blog_id");

       t.data(& blog::m_text, "blog_text");
       t.data(& blog::m_dt_creation, "date_creation");

       t.relationManyToOne(& blog::m_author, "author_id");
       t.relationOneToMany(& blog::m_commentX, "list_comment", "blog_id");
       t.relationManyToMany(& blog::m_categoryX, "list_category", "category_blog", "blog_id", "category_id");
    }}

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 :

- la s�rialisation automatique des donn�es ou collections de donn�es au format binaire, XML et JSON ;
- la r�flexion (ou introspection) permettant d'acc�der � la d�finition des classes param�tr�es dans le contexte QxOrm ainsi que l'appel automatique des m�thodes de classes.

    #include "../include/precompiled.h"

    #include <QtGui/qapplication.h>

    #include "../include/blog.h"
    #include "../include/author.h"
    #include "../include/comment.h"
    #include "../include/category.h"

    #include <QxOrm_Impl.h>

    int main(int argc, char * argv[])
    {
       // Initialisation de l'objet application du framework Qt
       QApplication app(argc, argv);

       // Param�tres de connexion � la base de donn�es
       qx::QxSqlDatabase::getSingleton()->setDriverName("QSQLITE");
       qx::QxSqlDatabase::getSingleton()->setDatabaseName("./qxBlog.sqlite");
       qx::QxSqlDatabase::getSingleton()->setHostName("localhost");
       qx::QxSqlDatabase::getSingleton()->setUserName("root");
       qx::QxSqlDatabase::getSingleton()->setPassword("");

       // Vide toutes les tables de la base de donn�es
       QSqlError daoError = qx::dao::delete_all<author>();
       daoError = qx::dao::delete_all<comment>();
       daoError = qx::dao::delete_all<category>();
       daoError = qx::dao::delete_all<blog>();

       // Cr�ation d'une liste de trois 'author'
       author_ptr author_1; author_1.reset(new author());
       author_ptr author_2; author_2.reset(new author());
       author_ptr author_3; author_3.reset(new author());

       author_1->m_id = "author_id_1"; author_1->m_name = "author_1";
       author_1->m_sex = author::male; author_1->m_birthdate = QDate::currentDate();
       author_2->m_id = "author_id_2"; author_2->m_name = "author_2";
       author_2->m_sex = author::female; author_2->m_birthdate = QDate::currentDate();
       author_3->m_id = "author_id_3"; author_3->m_name = "author_3";
       author_3->m_sex = author::female; author_3->m_birthdate = QDate::currentDate();

       list_author authorX;
       authorX.insert(author_1->m_id, author_1);
       authorX.insert(author_2->m_id, author_2);
       authorX.insert(author_3->m_id, author_3);

       // Insertion de la liste des trois 'author' dans la base de donn�es
       daoError = qx::dao::insert(authorX);
       qAssert(qx::dao::count<author>() == 3);

       // Cr�ation d'un clone de l'instance 'author_id_2'
       author_ptr author_clone = qx::clone(* author_2);
       qAssert(author_clone->m_id == "author_id_2");
       qAssert(author_clone->m_sex == author::female);

       // Construit une requ�te pour r�cup�rer uniquement les 'author' de type 'female', soit 'author_id_2' et 'author_id_3'
       qx::QxSqlQuery query("WHERE author.sex = :sex");
       query.bind(":sex", author::female);

       list_author list_of_female_author;
       daoError = qx::dao::fetch_by_query(query, list_of_female_author);
       qAssert(list_of_female_author.count() == 2);

       // Affiche la liste des 'author' de type 'female' dans un flux XML (ou JSON)
       qx::dump(list_of_female_author);

       // Cr�ation de trois 'category' pour classer les 'blog'
       category_ptr category_1 = category_ptr(new category());
       category_ptr category_2 = category_ptr(new category());
       category_ptr category_3 = category_ptr(new category());

       category_1->m_name = "category_1"; category_1->m_desc = "desc_1";
       category_2->m_name = "category_2"; category_2->m_desc = "desc_2";
       category_3->m_name = "category_3"; category_3->m_desc = "desc_3";

       { // Ouverture d'un 'scope' pour g�rer la destruction d'une connexion temporaire � la base de donn�es

       // Cr�ation d'une connexion temporaire � la base de donn�es et ouverture d'une transaction
       QSqlDatabase db = qx::QxSqlDatabase::getDatabase();
       bool bCommit = db.transaction();

       // Insertion de trois 'category' dans la base de donn�es en utilisant la connexion temporaire 'db'
       daoError = qx::dao::insert(category_1, (& db));    bCommit = (bCommit && ! daoError.isValid());
       daoError = qx::dao::insert(category_2, (& db));    bCommit = (bCommit && ! daoError.isValid());
       daoError = qx::dao::insert(category_3, (& db));    bCommit = (bCommit && ! daoError.isValid());

       qAssert(bCommit);
       qAssert(category_1->m_id != 0);
       qAssert(category_2->m_id != 0);
       qAssert(category_3->m_id != 0);

       // Fin de la transaction => 'commit' ou 'rollback' en cas d'erreur
       if (bCommit) { db.commit(); }
       else { db.rollback(); }

       } // Fermeture du 'scope' : l'instance 'db' est d�truite

       // Cr�ation d'un 'blog' � partir du nom de la classe (design pattern 'factory')
       boost::any blog_any = qx::create("blog");
       blog_ptr blog_1 = boost::any_cast<blog_ptr>(blog_any);
       blog_1->m_text = "blog_text_1";
       blog_1->m_dt_creation = QDateTime::currentDateTime();
       blog_1->m_author = author_1;

       // Insertion de 'blog_1' dans la base de donn�es avec la m�thode 'save()'
       daoError = qx::dao::save(blog_1);

       // Modification des propri�t�s de 'blog_1' et mise � jour dans la base de donn�es
       blog_1->m_text = "update blog_text_1";
       blog_1->m_author = author_2;
       daoError = qx::dao::save(blog_1);

       // Ajoute deux commentaires � 'blog_1'
       comment_ptr comment_1; comment_1.reset(new comment());
       comment_ptr comment_2; comment_2.reset(new comment());

       comment_1->m_text = "comment_1 text";
       comment_1->m_dt_create = QDateTime::currentDateTime();
       comment_1->m_blog = blog_1;
       comment_2->m_text = "comment_2 text";
       comment_2->m_dt_create = QDateTime::currentDateTime();
       comment_2->m_blog = blog_1;

       daoError = qx::dao::insert(comment_1);
       daoError = qx::dao::insert(comment_2);
       qAssert(qx::dao::count<comment>() == 2);

       // Associe deux 'category' � 'blog_1' => n�cessite une 3�me table pour la relation 'many-to-many'
       blog_1->m_categoryX.insert(category_1->m_id, category_1);
       blog_1->m_categoryX.insert(category_3->m_id, category_3);
       daoError = qx::dao::save_with_relation("list_category", blog_1);

       // R�cup�re avec une seule m�thode 'blog_1' et toutes ses relations dans la base de donn�es
       blog_ptr blog_tmp; blog_tmp.reset(new blog());
       blog_tmp->m_id = blog_1->m_id;
       daoError = qx::dao::fetch_by_id_with_all_relation(blog_tmp);

       qAssert(blog_tmp->m_commentX.count() == 2);
       qAssert(blog_tmp->m_categoryX.count() == 2);
       qAssert(blog_tmp->m_text == "update blog_text_1");
       qAssert(blog_tmp->m_author && blog_tmp->m_author->m_id == "author_id_2");

       // Affiche 'blog_tmp' provenant de la base de donn�es dans un flux XML (ou JSON)
       qx::dump(blog_tmp);

       // Invoque la m�thode 'age()' de la classe 'author' par le m�canisme de r�flexion (ou introspection)
       qx_bool bInvokeOk = qx::QxClassX::invoke("author", "age", author_1);
       qAssert(bInvokeOk);

       return 0;
    }

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 |