Files
XdlOrm/doc/qxorm_fr/faq.html
2026-04-03 11:32:07 +08:00

3768 lines
301 KiB
HTML
Raw Permalink Blame History

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=iso-8859-1">
<title>QxOrm : C++ Qt ORM Object Relational Mapping database library - QxEntityEditor : C++ Qt entities graphic editor
(data model designer and source code generator)</title>
<link rel='stylesheet' type='text/css' href='./resource/qxorm_style.css'>
<script type="text/javascript" src="./resource/jquery.min.js"></script>
<script type="text/javascript" src="./resource/qxorm_script.js"></script>
</head>
<body>
<table border="0" style="width: 80%" align="center">
<col>
<col>
<col>
<col>
<col>
<tbody>
<tr>
<td><a href="./home.html"><img alt="QxOrm" src="./resource/logo_qxorm_and_qxee.png" align="left" border="0"></a>
</td>
<td align="right" style="vertical-align:bottom">
<div id="qx_search">
<gcse:search></gcse:search>
</div>
</td>
<td width="15"></td>
<td align="right" style="vertical-align:bottom">
<img alt="Windows" src="./resource/logo_windows.gif" width="35" height="35">
<img alt="Linux" src="./resource/logo_linux.gif" width="35" height="35">
<img alt="Macintosh" src="./resource/logo_mac.gif" width="35" height="35">
</td>
<td width="70"><img alt="C++" src="./resource/logo_cpp.gif" width="50" height="50" align="right"></td>
</tr>
</tbody>
</table>
<hr style="width: 80%" align="center" size="1" color="#100D5A">
<table border="0" style="width: 80%" align="center">
<col>
<col>
<col>
<col>
<col>
<col>
<tbody>
<tr>
<td align="center"><a href="./home.html" class="btn_nav">Accueil</a></td>
<td align="center"><a href="./download.html" class="btn_nav">T<EFBFBD>l<EFBFBD>chargement</a></td>
<td align="center"><a href="./quick_sample.html" class="btn_nav">Exemple rapide</a></td>
<td align="center" onmouseover="showHideElementById('menu_tuto', true);"
onmouseout="showHideElementById('menu_tuto', false);">
<a href="./tutorial.html" class="btn_nav">Tutoriel (4)</a>
<table class="table_menu_tuto">
<tbody>
<tr>
<td>
<div id="menu_tuto" class="div_menu_tuto">
<a href="./tutorial_3.html" class="btn_sub_menu">install QxOrm</a><br />
<a href="./tutorial.html" class="btn_sub_menu">qxBlog</a><br />
<a href="./tutorial_2.html" class="btn_sub_menu">qxClientServer</a><br />
<a href="./tutorial_4.html" class="btn_sub_menu">QxEntityEditor videos</a>
</div>
</td>
</tr>
</tbody>
</table>
</td>
<td align="center" onmouseover="showHideElementById('menu_manual', true);"
onmouseout="showHideElementById('menu_manual', false);">
<a href="./manual.html" class="btn_nav">Manuel (2)</a>
<table class="table_menu_manual">
<tbody>
<tr>
<td>
<div id="menu_manual" class="div_menu_manual">
<a href="./manual.html" class="btn_sub_menu">Manuel QxOrm</a><br />
<a href="./manual_qxee.html" class="btn_sub_menu">Manuel QxEntityEditor</a><br />
</div>
</td>
</tr>
</tbody>
</table>
</td>
<td align="center"><a href="./link.html" class="btn_nav">Forum</a></td>
<td align="center"><a href="./customer.html" class="btn_nav">Nos clients</a></td>
</tr>
</tbody>
</table>
<hr style="width: 80%" align="center" size="1" color="#100D5A">
<table border="0" style="width: 80%" align="center">
<col>
<col>
<col>
<col>
<col>
<col>
<tbody>
<tr>
<td align="left" valign="top">
<font size="2" class="txt_with_shadow">QxOrm &gt;&gt; Faq</font>
</td>
<td align="right" valign="top">
<table cellspacing="0" cellpadding="1">
<col>
<col>
<tbody>
<tr>
<td align="right" valign="top">
<font size="2" class="txt_with_shadow">Version courante :&nbsp;</font>
</td>
<td align="left" valign="top">
<font size="2" class="txt_with_shadow">QxOrm 1.5.0 - <a href="../doxygen/index.html"
target="_blank">documentation en ligne de la biblioth<74>que QxOrm</a> - <a
href="https://github.com/QxOrm/QxOrm" target="_blank">GitHub</a></font>
</td>
</tr>
<tr>
<td align="right" valign="top">
<font size="2" class="txt_with_shadow"></font>
</td>
<td align="left" valign="top">
<font size="2" class="txt_with_shadow">QxEntityEditor 1.2.8</font>
</td>
</tr>
</tbody>
</table>
</td>
<td width="10px"></td>
<td width="40px" height="30px"><a href="../qxorm_fr/faq.html"><img alt="Version fran<61>aise du site"
src="./resource/FR.png" width="40" height="30" border="0"></a></td>
<td width="40px" height="30px"><a href="../qxorm_en/faq.html"><img alt="Web site english version"
src="./resource/GB.png" width="40" height="30" border="0"></a></td>
<td width="40px" height="30px"><a href="http://sites.google.com/site/qxormpostgres/" target="_blank"><img alt=""
src="./resource/ES.png" width="40" height="30" border="0"></a></td>
</tr>
</tbody>
</table>
<table border="1" frame="vsides" rules="cols" style="width: 80%" align="center" cellpadding="6" bgcolor="#F2F2F4">
<col>
<tbody>
<tr>
<td align="justify">
<table border="0" style="width: 100%" align="center">
<col>
<col>
<tbody>
<tr>
<td>
<ul>
<li><a href="#faq_10">Qu'est-ce que QxOrm ?</a><br>
</li>
<li><a href="#faq_15">Qu'est-ce que QxEntityEditor ?</a><br>
</li>
<li><a href="#faq_20">Comment contacter QxOrm pour indiquer un bug ou poser une question ?</a><br>
</li>
<li><a href="#faq_30">Comment installer et compiler QxOrm ?</a><br>
</li>
<li><a href="#faq_40">Quelles sont les bases de donn<6E>es prises en compte par QxOrm ?</a><br>
</li>
<li><a href="#faq_50">Pourquoi QxOrm est d<>pendant de deux biblioth<74>ques : boost et Qt ?</a><br>
</li>
<li><a href="#faq_60">Pourquoi QxOrm n<>cessite un en-t<>te pr<70>compil<69> (precompiled header) pour
pouvoir <20>tre utilis<69> ?</a><br>
</li>
<li><a href="#faq_70">Est-il possible d'acc<63>l<EFBFBD>rer les temps de compilation d'un projet ?</a><br>
</li>
<li><a href="#faq_75">Quels sont les diff<66>rents types de <i>serialization</i> disponibles ?</a><br>
</li>
<li><a href="#faq_80">Pourquoi QxOrm fournit un nouveau type de container
<i>qx::QxCollection&lt;Key, Value&gt;</i> ?</a><br>
</li>
<li><a href="#faq_81">Pourquoi QxOrm fournit un nouveau type de pointeur intelligent
<i>qx::dao::ptr&lt;T&gt;</i> ?</a><br>
</li>
<li><a href="#faq_90">Faut-il utiliser <i>QString</i> ou <i>std::string</i> ?</a><br>
</li>
<li><a href="#faq_95">Faut-il utiliser les pointeurs intelligents <i>smart-pointer</i> ?</a><br>
</li>
<li><a href="#faq_100">La cl<63> primaire est de type <i>long</i> par d<>faut. Est-il possible
d'utiliser une cl<63> de type <i>QString</i> ou autre ?</a><br>
</li>
<li><a href="#faq_101">Comment d<>finir une cl<63> primaire sur plusieurs colonnes (<i>composite
key</i>) ?</a><br>
</li>
<li><a href="#faq_105">Comment enregistrer des membres <i>private</i> ou <i>protected</i> dans le
contexte QxOrm ?</a><br>
</li>
<li><a href="#faq_110">Comment activer/d<>sactiver le module <i>QxMemLeak</i> pour la d<>tection
automatique des fuites m<>moires ?</a><br>
</li>
<li><a href="#faq_120">Comment g<>rer la notion d'h<>ritage avec la base de donn<6E>es ?</a><br>
</li>
<li><a href="#faq_130">Comment utiliser les <i>Trigger</i> ?</a><br>
</li>
<li><a href="#faq_140">Comment d<>clarer une classe abstraite dans le contexte QxOrm ?</a><br>
</li>
<li><a href="#faq_150">Comment d<>clarer une classe d<>finie dans un espace de nom (<i>namespace</i>)
dans le contexte QxOrm ?</a><br>
</li>
<li><a href="#faq_160">Comment utiliser le m<>canisme de suppression logique (<i>soft delete</i>)
?</a><br>
</li>
<li><a href="#faq_170">Comment utiliser les sessions (classe <i>qx::QxSession</i>) pour simplifier
la gestion des transactions des bases de donn<6E>es (C++ RAII) ?</a><br>
</li>
<li><a href="#faq_180">Comment persister un type dont on ne poss<73>de pas le code source (classe
provenant d'une biblioth<74>que tierce par exemple) ?</a><br>
</li>
<li><a href="#faq_190">Comment utiliser le moteur d'introspection (ou r<>flexion) de la biblioth<74>que
QxOrm ?</a><br>
</li>
<li><a href="#faq_200">Comment d<>clarer automatiquement les m<>ta-propri<72>t<EFBFBD>s de Qt (d<>finies par la
macro <i>Q_PROPERTY</i>) dans le contexte QxOrm ?</a><br>
</li>
<li><a href="#faq_210">Comment construire une requ<71>te pour interroger la base de donn<6E>es sans <20>crire
de SQL avec la classe <i>qx::QxSqlQuery</i> ?</a><br>
</li>
<li><a href="#faq_220">Comment utiliser le cache (fonctions du namespace <i>qx::cache</i>) pour
stocker tous types de donn<6E>es ?</a><br>
</li>
<li><a href="#faq_230">Comment g<>n<EFBFBD>rer le sch<63>ma SQL (cr<63>ation et mise <20> jour des tables) en
fonction des classes persistantes C++ d<>finies dans le contexte QxOrm ?</a><br>
</li>
<li><a href="#faq_240">Comment associer un type SQL <20> une classe C++ ?</a><br>
</li>
<li><a href="#faq_250">Comment utiliser le module <i>QxValidator</i> pour valider automatiquement
les donn<6E>es ?</a><br>
</li>
<li><a href="#faq_260">Comment utiliser l'interface <i>qx::IxPersistable</i> ?</a><br>
</li>
<li><a href="#faq_270">Comment utiliser le moteur de relations pour r<>cup<75>rer des donn<6E>es associ<63>es
<20> plusieurs tables ?</a><br>
</li>
<li><a href="#faq_280">Comment appeler une proc<6F>dure stock<63>e ou une requ<71>te SQL personnalis<69>e
?</a><br>
</li>
<li><a href="#faq_290">Comment utiliser la classe <i>qx::QxDaoAsync</i> pour appeler des requ<71>tes de
mani<6E>re asynchrone (multi-thread) ?</a><br>
</li>
<li><a href="#faq_300">Comment utiliser le module <i>QxModelView</i> pour travailler avec le moteur
<i>model/view</i> de Qt (Qt widgets et vues QML) ?</a><br>
</li>
</ul>
</td>
<td width="200" align="center" valign="top"><a href="./resource/qt_ambassador_logo.png"
target="_blank"><img alt="qt_ambassador" src="./resource/qt_ambassador_logo_150x150.png" width="150"
height="150" border="0"></a><br>
<b>
<font size="2">QxOrm library has been accepted into the <a
href="http://forum.qt.io/category/24/qt-ambassador-program" target="_blank">Qt Ambassador
Program</a></font>
</b>
</td>
</tr>
</tbody>
</table>
<br>
<a name="faq_10"><u><b>Qu'est-ce que QxOrm ?</b></u></a><br><br>
<table border="0" style="width: 100%" align="center">
<col>
<col>
<tbody>
<tr>
<td valign="middle" width="30"></td>
<td align="justify">
<b>QxOrm est une biblioth<74>que C++ open source de gestion de donn<6E>es (Object Relational Mapping,
ORM).</b><br>
<b>QxOrm</b> est d<>velopp<70> XDL Teamarty, Ing<6E>nieur en d<>veloppement logiciel depuis 2003.<br>
<br>
<20> partir d'une simple <i>fonction de param<61>trage</i> (que l'on peut comparer avec un fichier de
mapping XML <i>Hibernate</i>), vous aurez acc<63>s aux fonctionnalit<69>s suivantes :
<ul>
<li>
<font style="background-color:yellow"><b>persistance</b></font> : communication avec de nombreuses
bases de donn<6E>es (avec support des relations <i>1-1</i>, <i>1-n</i>, <i>n-1</i> et <i>n-n</i>) ;
</li>
<li>
<font style="background-color:yellow"><b>s<EFBFBD>rialisation</b></font> des donn<6E>es (flux binaire, XML
et JSON) ;
</li>
<li>moteur de <font style="background-color:yellow"><b>r<EFBFBD>flexion</b></font> (ou <font
style="background-color:yellow"><b>introspection</b></font>) pour acc<63>der aux classes, attributs
et invoquer des m<>thodes.
</li>
</ul>
<b>QxOrm</b> est d<>pendant des excellentes biblioth<74>ques <a href="http://www.boost.org/"
target="_blank"><b>boost</b></a> (compatible <20> partir de la version 1.38) et <a
href="http://www.qt.io/" target="_blank"><b>Qt</b></a> (compatible <20> partir de la version
4.5.0).<br>
La biblioth<74>que <b>QxOrm</b> a <20>t<EFBFBD> retenue pour faire partie du programme <a
href="http://forum.qt.io/category/24/qt-ambassador-program" target="_blank"><b>Qt
Ambassador</b></a>.
<br><br>
</td>
</tr>
</tbody>
</table>
<br>
<a name="faq_15"><u><b>Qu'est-ce que QxEntityEditor ?</b></u></a><br><br>
<table border="0" style="width: 100%" align="center">
<col>
<col>
<tbody>
<tr>
<td valign="middle" width="30"></td>
<td align="justify">
<b>QxEntityEditor</b> est un <20>diteur graphique pour la biblioth<74>que <b>QxOrm</b> :
<b>QxEntityEditor</b> permet de g<>rer graphiquement le mod<6F>le d'entit<69>s.<br>
<b>QxEntityEditor</b> est multi-plateforme (disponible pour Windows, Linux et Mac OS X) et g<>n<EFBFBD>re du
code natif pour tous les environnements : bureau (Windows, Linux, Mac OS X), embarqu<71> et mobile
(Android, iOS, Windows Phone, Raspberry Pi, etc.).<br>
<a href="./tutorial_4.html">Une vid<69>o de pr<70>sentation de l'application <b>QxEntityEditor</b> est
disponible</a>.<br>
<br>
<b>QxEntityEditor</b> est bas<61> sur un syst<73>me de plugins et propose diverses fonctionnalit<69>s pour
importer/exporter le mod<6F>le de donn<6E>es :
<ul>
<li>g<EFBFBD>n<EFBFBD>ration automatique du code C++ (classes persistantes enregistr<74>es dans le contexte QxOrm) ;
</li>
<li>g<EFBFBD>n<EFBFBD>ration automatique des scripts SQL DDL (sch<63>ma de base de donn<6E>es) pour les bases SQLite,
MySQL, PostgreSQL, Oracle et MS SQL Server ;</li>
<li>supporte l'<27>volution du sch<63>ma de base de donn<6E>es pour chaque version d'un projet (<i>ALTER
TABLE</i>, <i>ADD COLUMN</i>, <i>DROP INDEX</i>, etc.) ;</li>
<li>g<EFBFBD>n<EFBFBD>ration automatique des classes C++ de services pour transf<73>rer le mod<6F>le de donn<6E>es sur le
r<>seau, en utilisant le module <a href="../doxygen/html/group___qx_service.html"
target="_blank">QxService</a>, pour cr<63>er rapidement des applications client/serveur ;</li>
<li>importation automatique des structures de bases de donn<6E>es existantes (par connexion ODBC) pour
les bases SQLite, MySQL, PostgreSQL, Oracle et MS SQL Server ;</li>
<li>parce que chaque projet est diff<66>rent, QxEntityEditor propose plusieurs outils pour
personnaliser les fichiers g<>n<EFBFBD>r<EFBFBD>s (notamment un moteur javascript et un d<>bogueur int<6E>gr<67>).</li>
</ul>
<a href="../qxentityeditor/resource/qxee_sample.png" target="_blank"><img alt="QxEntityEditor"
src="../qxentityeditor/resource/qxee_sample_small.png" border="0" class="img_with_shadow"></a>
<br><br>
<b>QxEntityEditor</b> est d<>velopp<70> XDL Teamarty, Ing<6E>nieur en d<>veloppement logiciel depuis 2003.<br>
<br><br>
</td>
</tr>
</tbody>
</table>
<br>
<a name="faq_20"><u><b>Comment contacter QxOrm pour indiquer un bug ou poser une question
?</b></u></a><br><br>
<table border="0" style="width: 100%" align="center">
<col>
<col>
<tbody>
<tr>
<td valign="middle" width="30"></td>
<td align="justify">
Si vous trouvez un bug ou si vous avez une question concernant le fonctionnement de la biblioth<74>que
<b>QxOrm</b>,
vous pouvez envoyer un mail <20> : <u><i>support@qxorm.com</i></u>.<br>
Un forum (en anglais) d<>di<64> <20> <b>QxOrm</b> est disponible <a href="https://www.qxorm.com/forum/phpbb/"
target="_blank">en cliquant ici</a>.<br>
Vous pouvez <20>galement retrouver la communaut<75> fran<61>aise de <b>QxOrm</b> sur <a
href="http://www.developpez.net/forums/f1563/c-cpp/bibliotheques/qt/bases-donnees/qxorm/"
target="_blank">le forum de Developpez.com</a>.
</td>
</tr>
</tbody>
</table>
<br><br>
<a name="faq_30"><u><b>Comment installer et compiler QxOrm ?</b></u></a><br><br>
<table border="0" style="width: 100%" align="center">
<col>
<col>
<tbody>
<tr>
<td valign="middle" width="30"></td>
<td align="justify">
<a href="./tutorial_3.html">Un tutoriel pour installer un environnement de d<>veloppement avec QxOrm
sous Windows est disponible en cliquant ici.</a><br />
<br />
<b>QxOrm</b> utilise le processus <i>qmake</i> de la biblioth<74>que <b>Qt</b> pour g<>n<EFBFBD>rer les
<i>makefile</i> et compiler le projet.<br>
<i>qmake</i> est multiplateforme et fonctionne parfaitement sous Windows, Linux (Unix) et Mac.<br>
Pour compiler <b>QxOrm</b>, il suffit d'ex<65>cuter les commandes suivantes :<br>
<br>
<i>qmake</i><br>
<i>make debug</i><br>
<i>make release</i><br>
<br>
Sous <b>Windows</b>, des fichiers <i>*.vcproj</i> et <i>*.sln</i> sont disponibles pour les <20>diteurs
<b>Visual C++ 2008</b>, <b>Visual C++ 2010</b> et <b>Visual C++ 2012</b>.<br>
Les fichiers <i>*.pro</i> sont lisibles par l'<27>diteur <b>Qt Creator</b>, et des plugins existent
permettant de s'interfacer avec de nombreux <20>diteurs C++.<br>
Les fichiers <i>mingw_build_all_debug.bat</i> et <i>mingw_build_all_release.bat</i> pr<70>sents dans le
dossier <i>./tools/</i> permettent de compiler rapidement QxOrm ainsi que tous les tests avec le
compilateur <b>MinGW</b> sous Windows.<br>
Les fichiers <i>gcc_build_all_debug.sh</i> et <i>gcc_build_all_release.sh</i> pr<70>sents dans le dossier
<i>./tools/</i> permettent de compiler rapidement QxOrm ainsi que tous les tests avec <b>GCC</b> sous
<b>Linux</b>.<br>
Enfin, les fichiers <i>osx_build_all_debug.sh</i> et <i>osx_build_all_release.sh</i> pr<70>sents dans le
dossier <i>./tools/</i> permettent de compiler rapidement QxOrm ainsi que tous les tests sous
<b>Mac</b> (merci <20> Dominique Billet pour l'<27>criture des scripts).<br>
<br>
<b>Remarque :</b> suivant l'environnement de d<>veloppement, il peut <20>tre n<>cessaire de modifier le
fichier <u><b>QxOrm.pri</b></u> pour param<61>trer la configuration de la biblioth<74>que <b>boost</b> :<br>
<br>
<i>QX_BOOST_INCLUDE_PATH = $$quote(D:/Dvlp/_Libs/Boost/1_42/include)<br>
QX_BOOST_LIB_PATH = $$quote(D:/Dvlp/_Libs/Boost/1_42/lib_shared)<br>
QX_BOOST_LIB_SERIALIZATION_DEBUG = "boost_serialization-vc90-mt-gd-1_42"<br>
QX_BOOST_LIB_SERIALIZATION_RELEASE = "boost_serialization-vc90-mt-1_42"<br></i>
</td>
</tr>
</tbody>
</table>
<br><br>
<a name="faq_40"><u><b>Quelles sont les bases de donn<6E>es prises en compte par QxOrm ?</b></u></a><br><br>
<table border="0" style="width: 100%" align="center">
<col>
<col>
<tbody>
<tr>
<td valign="middle" width="30"></td>
<td align="justify">
<b>QxOrm</b> utilise le moteur <a href="http://doc.qt.io/qt-5/sql-programming.html"
target="_blank"><i>QtSql</i></a> de <b>Qt</b> bas<61> sur un syst<73>me de plugin.<br>
Une liste d<>taill<6C>e des bases de donn<6E>es support<72>es est disponible sur le site de Qt <a
href="http://doc.qt.io/qt-5/sql-driver.html" target="_blank">en cliquant ici</a>.<br>
Le plugin <i>ODBC</i> (<i>QODBC</i>) assure une compatibilit<69> avec de nombreuses bases de donn<6E>es.<br>
Pour des performances optimales, il est conseill<6C> d'utiliser un plugin sp<73>cifique <20> une base de
donn<6E>es :
<ul>
<li><i>QMYSQL</i> : MySQL ;
</li>
<li><i>QPSQL</i> : PostgreSQL (versions 7.3 and above) ;
</li>
<li><i>QOCI</i> : Oracle Call Interface Driver ;
</li>
<li><i>QSQLITE</i> : SQLite version 3 ;
</li>
<li><i>QDB2</i> : IBM DB2 (version 7.1 and above) ;
</li>
<li><i>QIBASE</i> : Borland InterBase ;
</li>
<li><i>QTDS</i> : Sybase Adaptive Server.
</li>
</ul>
</td>
</tr>
</tbody>
</table>
<br>
<a name="faq_50"><u><b>Pourquoi QxOrm est d<>pendant de deux biblioth<74>ques : boost et Qt ?</b></u></a><br><br>
<table border="0" style="width: 100%" align="center">
<col>
<col>
<tbody>
<tr>
<td valign="middle" width="30"></td>
<td align="justify">
<b>QxOrm</b> utilise de nombreuses fonctionnalit<69>s disponibles dans les excellentes biblioth<74>ques
<b>boost</b> et <b>Qt</b>.<br>
De plus, ces deux biblioth<74>ques sont utilis<69>es dans de nombreux projets <20> la fois professionnels et
open-source.<br>
Il existe un grand nombre de forums, de tutoriaux, et toute une communaut<75> pour r<>pondre <20> toutes les
probl<62>matiques que vous pourriez rencontrer.<br>
L'objectif de <b>QxOrm</b> n'est pas de red<65>velopper des fonctionnalit<69>s qui existent d<>j<EFBFBD> mais de
fournir un outil performant d'acc<63>s aux bases de donn<6E>es
comme il en existe dans d'autres langages (<i>Java</i> avec <i>Hibernate</i>, <i>.Net</i> avec
<i>NHibernate</i>, <i>Ruby</i>, <i>Python</i>, etc.).<br><br>
<table border="0" style="width: 100%" align="center">
<col>
<col>
<tbody>
<tr>
<td valign="middle" width="161" align="center"><a href="http://www.qt.io/" target="_blank"><img
alt="Qt" src="./resource/logo_qt.jpg" width="42" height="50" border="0"></a></td>
<td align="justify"><b>Qt</b> : biblioth<74>que compl<70>te : IHM
(<i>QtGui</i>), r<>seau (<i>QtNetwork</i>), XML (<i>QtXml</i>), base de donn<6E>es
(<i>QtSql</i>), etc.<br>
La documentation est excellente et le code C++ <20>crit <20> partir
de cette biblioth<74>que est <20> la fois performant et simple de
compr<70>hension.<br>
Depuis le rachat par Nokia puis Digia et sa nouvelle licence LGPL, Qt est
sans contexte la biblioth<74>que phare du moment.<br>
QxOrm est compatible avec les principaux objets d<>finis par Qt
: <i>QObject, QString, QDate, QTime, QDateTime, QList, QHash,
QSharedPointer, QScopedPointer, etc.</i><br>
Il est conseill<6C> d'installer et d'utiliser la derni<6E>re version
de Qt disponible <20> l'adresse suivante : <a href="http://www.qt.io/"
target="_blank">http://www.qt.io/</a></td>
</tr>
</tbody>
</table>
<p></p>
<table border="0" style="width: 100%" align="center">
<col>
<col>
<tbody>
<tr>
<td valign="middle" width="161" align="center"><a href="http://www.boost.org/"
target="_blank"><img alt="boost" src="./resource/logo_boost.jpg" width="161" height="50"
border="0"></a></td>
<td align="justify"><b>boost</b> : de nombreux modules de la
biblioth<74>que boost font partie de la nouvelle norme C++.<br>
C'est une biblioth<74>que reconnue pour sa qualit<69>, son code 'C++
moderne', sa documentation, sa portabilit<69>, etc.<br>
QxOrm utilise les fonctionnalit<69>s suivantes de boost :
<i>smart_pointer, serialization, type_traits,
multi_index_container, unordered_container, any, tuple,
foreach, function.</i><br>
Il est conseill<6C> d'installer et d'utiliser la derni<6E>re version
de boost disponible <20> l'adresse suivante : <a href="http://www.boost.org/"
target="_blank">http://www.boost.org/</a>
</td>
</tr>
</tbody>
</table>
</td>
</tr>
</tbody>
</table>
<br><br>
<a name="faq_60"><u><b>Pourquoi QxOrm n<>cessite un en-t<>te pr<70>compil<69> (precompiled header) pour pouvoir <20>tre
utilis<69> ?</b></u></a><br><br>
<table border="0" style="width: 100%" align="center">
<col>
<col>
<tbody>
<tr>
<td valign="middle" width="30"></td>
<td align="justify">
<b>QxOrm</b> utilise les techniques de <b>m<EFBFBD>taprogrammation C++</b> pour fournir une grande partie de
ses fonctionnalit<69>s.<br>
Vous n'avez pas besoin de savoir utiliser la m<>taprogrammation pour travailler avec la biblioth<74>que
QxOrm.<br>
En effet, QxOrm se veut simple d'utilisation et un code C++ <20>crit avec Qt et QxOrm est facile <20> lire,
donc facile <20> d<>velopper et <20> maintenir.<br><br>
Cependant, la m<>taprogrammation est couteuse en temps de compilation.<br>
En utilisant un fichier <i>precompiled.h</i>, un projet C++ se compilera beaucoup plus vite.<br>
Un seul fichier d'en-t<>te est n<>cessaire pour disposer de l'ensemble des fonctionnalit<69>s de QxOrm : le
fichier <i>QxOrm.h</i>.
</td>
</tr>
</tbody>
</table>
<br><br>
<a name="faq_70"><u><b>Est-il possible d'acc<63>l<EFBFBD>rer les temps de compilation d'un projet ?</b></u></a><br><br>
<table border="0" style="width: 100%" align="center">
<col>
<col>
<tbody>
<tr>
<td valign="middle" width="30"></td>
<td align="justify">
Oui, si la <i>serialization</i> des donn<6E>es au format XML n'est pas utilis<69>e dans le projet, vous
pouvez d<>sactiver cette fonctionnalit<69>.<br>
Les temps de compilation seront alors r<>duits mais vous n'aurez plus acc<63>s au namespace
<i>qx::serialization:xml</i>.<br>
Pour d<>sactiver la <i>serialization XML</i>, il faut ouvrir le fichier de configuration
<i>QxOrm.pri</i> et supprimer (ou mettre en commentaire) l'option de compilation
<b><i>_QX_ENABLE_BOOST_SERIALIZATION_XML</i></b>.<br>
Une recompilation de la biblioth<74>que QxOrm est n<>cessaire pour prendre en compte cette
modification.<br>
<br>
Une autre possibilit<69> est d'utiliser les classes <i>polymorphiques</i> de la biblioth<74>que <a
href="http://www.boost.org/doc/libs/release/libs/serialization/doc/index.html"
target="_blank"><i>boost::serialization</i></a> (<28> la place des classes <i>template</i>).<br>
Cette fonctionnalit<69> r<>duit les temps de compilation ainsi que la taille de l'<27>xecutable g<>n<EFBFBD>r<EFBFBD>.<br>
En contre-partie, la vitesse d'ex<65>cution du programme sera r<>duite puisqu'une partie du travail
effectu<74> lors de la compilation devra <20>tre r<>alis<69> <20> l'ex<65>cution de l'application.<br>
Pour utiliser cette fonctionnalit<69> dans <b>QxOrm</b>, vous devez activer l'option de compilation
<b><i>_QX_ENABLE_BOOST_SERIALIZATION_POLYMORPHIC</i></b> dans le fichier de configuration
<i>QxOrm.pri</i>.<br>
<b>Attention</b> : les fonctions de <i>serialization</i> seront alors accessibles depuis les
<i>namespace</i> suivants : <i>qx::serialization::polymorphic_binary</i>,
<i>qx::serialization::polymorphic_text</i> et <i>qx::serialization::polymorphic_xml</i>.<br>
Une recompilation de la biblioth<74>que QxOrm est n<>cessaire pour prendre en compte cette
modification.<br>
<br>
Enfin, il est <20>galement possible d'utiliser la macro <i>Q_PROPERTY</i> pour d<>clarer les propri<72>t<EFBFBD>s si
la classe h<>rite du type <i>QObject</i>.<br>
Dans ce cas, il existe deux mani<6E>res diff<66>rentes pour enregistrer les propri<72>t<EFBFBD>s dans le contexte
QxOrm, dont une qui r<>duit sensiblement les temps de compilation du projet.<br>
Pour plus d'informations sur cette fonctionnalit<69>, <a href="./faq.html#faq_200">rendez-vous sur cette
Question-R<>ponse de la FAQ</a>.<br>
<br>
<b>Remarque :</b> il est <20>galement n<>cessaire de s'assurer que toutes les optimisations propos<6F>es par
le compilateur sont activ<69>es, notamment au niveau de la compilation parall<6C>le sur plusieurs
processeurs :
<ul>
<li><b>MSVC++</b> : utiliser la variable d'environnement <b>SET CL=/MP</b></li>
<li><b>GCC</b> et <b>Clang</b> : pr<70>ciser le nombre de processeurs utilis<69>s en param<61>tre du process
<i>make</i>, par exemple pour 8 coeurs : <b>SET MAKE_COMMAND=make -j8</b>
</li>
</ul>
</td>
</tr>
</tbody>
</table>
<br><br>
<a name="faq_75"><u><b>Quels sont les diff<66>rents types de <i>serialization</i> disponibles
?</b></u></a><br><br>
<table border="0" style="width: 100%" align="center">
<col>
<col>
<tbody>
<tr>
<td valign="middle" width="30"></td>
<td align="justify">
<b>QxOrm</b> utilise le framework de <i>serialization</i> propos<6F> par la biblioth<74>que <a
href="http://www.boost.org/doc/libs/release/libs/serialization/doc/index.html"
target="_blank">boost</a>.<br>
Il existe plusieurs types de serialization disponibles : <i>binaire, XML, JSON, texte, etc.</i><br>
Le fichier de configuration <i>QxOrm.pri</i> permet d'activer et/ou d<>sactiver les diff<66>rents types de
serialization.<br>
<br>
Chaque type de serialization poss<73>de ses propres caract<63>ristiques :
<ul>
<li><b>binary</b> : <i>smallest, fastest, non-portable</i> ;
</li>
<li><b>text</b> : <i>larger, slower, portable</i> ;
</li>
<li><b>XML</b> : <i>largest, slowest, portable</i>.
</li>
</ul>
<b>Remarque :</b> le type <b>binary</b> n'est pas portable, ce qui signifie que des donn<6E>es ne peuvent
pas s'<27>changer entre un syt<79>me Windows et un syst<73>me Unix par exemple.<br>
Si vous devez faire transiter des donn<6E>es sur un r<>seau <20> travers plusieurs syst<73>mes d'exploitation,
il faut utiliser le type de serialization <b>text</b> ou <b>XML</b>.<br>
<b>QxOrm</b> propose <20>galement une autre solution : le type de serialization <b><a
href="http://epa.codeplex.com/" target="_blank">portable_binary</a></b>.<br>
Le type <b>portable_binary</b> poss<73>de les m<>mes caract<63>ristiques que le type <b>binary</b> et permet
d'<27>changer des donn<6E>es de mani<6E>re portable.<br>
Cependant, ce type de serialization n'est pas propos<6F> officiellement par la biblioth<74>que <b>boost</b>,
il est donc n<>cessaire de tester avant de l'utiliser dans un logiciel en production.
</td>
</tr>
</tbody>
</table>
<br><br>
<a name="faq_80"><u><b>Pourquoi QxOrm fournit un nouveau type de container <i>qx::QxCollection&lt;Key,
Value&gt;</i> ?</b></u></a><br><br>
<table border="0" style="width: 100%" align="center">
<col>
<col>
<tbody>
<tr>
<td valign="middle" width="30"></td>
<td align="justify">
Il existe de nombreux <i>container</i> dans les biblioth<74>ques <b>stl</b>, <b>boost</b> et
<b>Qt</b>.<br>
Il est donc l<>gitime de se poser cette question : <20> quoi sert <i>qx::QxCollection&lt;Key,
Value&gt;</i> ?<br>
<i><a href="../doxygen/html/classqx_1_1_qx_collection.html" target="_blank">qx::QxCollection&lt;Key,
Value&gt;</a></i> est un nouveau <i>container</i> (bas<61> sur l'excellente biblioth<74>que <a
href="http://www.boost.org/doc/libs/release/libs/multi_index/doc/index.html"
target="_blank"><i>boost::multi_index_container</i></a>) qui poss<73>de les fonctionnalit<69>s suivantes :
<ul>
<li>conserve l'ordre d'insertion des <20>l<EFBFBD>ments dans la liste ;
</li>
<li>acc<EFBFBD>s rapide <20> un <20>l<EFBFBD>ment par son index : <20>quivaut <20> <i>std::vector&lt;T&gt;</i> ou
<i>QList&lt;T&gt;</i> par exemple ;
</li>
<li>acc<EFBFBD>s rapide <20> un <20>l<EFBFBD>ment par une cl<63> (<i>hash-map</i>) : <20>quivaut <20> <i>QHash&lt;Key,
Value&gt;</i> ou <i>boost::unordered_map&lt;Key, Value&gt;</i> par exemple ;
</li>
<li>fonctions de tri sur le type <i>Key</i> et sur le type <i>Value</i>.
</li>
</ul>
<b>Remarque :</b>
<i>qx::QxCollection&lt;Key, Value&gt;</i> est compatible avec la macro <i>foreach</i> fournie par la
biblioth<74>que <b>Qt</b> ainsi que par la macro <a
href="http://www.boost.org/doc/libs/release/doc/html/foreach.html"
target="_blank"><i>BOOST_FOREACH</i></a> fournie par la biblioth<74>que <b>boost</b>.<br>
Cependant, chaque <20>l<EFBFBD>ment renvoy<6F> par ces deux macros correspond <20> un objet de type
<i>std::pair&lt;Key, Value&gt;</i>.<br>
Pour obtenir un r<>sultat 'plus naturel' et plus lisible, il est conseill<6C> d'utiliser la macro
<i>_foreach</i> : cette macro utilise <i>BOOST_FOREACH</i> pour tous les <i>container</i> sauf pour
<i>qx::QxCollection&lt;Key, Value&gt;</i>.<br>
Dans ce cas, l'<27>l<EFBFBD>ment renvoy<6F> correspond au type <i>Value</i> (voir par la suite l'exemple
d'utilisation).<br>
La macro <i>_foreach</i> est donc compatible avec tous les <i>container</i> (<b>stl</b>, <b>Qt</b>,
<b>boost</b>, etc.) puisqu'elle utilise la macro <i>BOOST_FOREACH</i>.<br><br>
<b>Autre Remarque :</b>
<i>qx::QxCollection&lt;Key, Value&gt;</i> est particuli<6C>rement adapt<70> pour recevoir des donn<6E>es issues
d'une base de donn<6E>es.<br>
En effet, ces donn<6E>es peuvent <20>tre tri<72>es (en utilisant <i>ORDER BY</i> dans une requ<71>te SQL par
exemple), il est donc important de conserver l'ordre d'insertion des <20>l<EFBFBD>ments dans la liste.<br>
De plus, chaque donn<6E>e issue d'une base de donn<6E>es poss<73>de un identifiant unique. Il est donc
int<6E>ressant de pouvoir acc<63>der <20> un <20>l<EFBFBD>ment en fonction de cet identifiant unique de mani<6E>re
extr<74>mement rapide (<i>hash-map</i>).<br><br>
<b>Exemple d'utilisation de la collection <i>qx::QxCollection&lt;Key, Value&gt;</i> :</b><br>
<br>
<table border="1" bgcolor="#FFFFFF">
<col>
<tbody>
<tr>
<td>
<pre><span class="comment">/* d<>finition d'une classe drug avec 3 propri<72>t<EFBFBD>s : 'code', 'name', 'description' */</span><span class="keyword">
class</span> drug<span class="operator"> {</span><span class="keyword"> public</span><span class="operator">:</span> QString code<span class="operator">;</span> QString name<span class="operator">;</span> QString desc<span class="operator">; };</span><span class="comment">
/* pointeur intelligent associ<63> <20> la classe drug */</span><span class="keyword">
typedef</span> boost<span class="operator">::</span>shared_ptr<span class="operator">&lt;</span>drug<span class="operator">&gt;</span> drug_ptr<span class="operator">;</span><span class="comment">
/* collection de drugs (acc<63>s rapide <20> un <20>l<EFBFBD>ment de la collection par la propri<72>t<EFBFBD> 'code') */</span>
qx<span class="operator">::</span>QxCollection<span class="operator">&lt;</span>QString<span class="operator">,</span> drug_ptr<span class="operator">&gt;</span> lstDrugs<span class="operator">;</span><span class="comment">
/* cr<63>ation de 3 nouveaux drugs */</span>
drug_ptr d1<span class="operator">;</span> d1<span class="operator">.</span>reset<span class="operator">(</span><span class="keyword">new</span> drug<span class="operator">());</span> d1<span class="operator">-&gt;</span>code<span class="operator"> =</span><span class="string"> "code1"</span><span class="operator">;</span> d1<span class="operator">-&gt;</span>name<span class="operator"> =</span><span class="string"> "name1"</span><span class="operator">;</span> d1<span class="operator">-&gt;</span>desc<span class="operator"> =</span><span class="string"> "desc1"</span><span class="operator">;</span>
drug_ptr d2<span class="operator">;</span> d2<span class="operator">.</span>reset<span class="operator">(</span><span class="keyword">new</span> drug<span class="operator">());</span> d2<span class="operator">-&gt;</span>code<span class="operator"> =</span><span class="string"> "code2"</span><span class="operator">;</span> d2<span class="operator">-&gt;</span>name<span class="operator"> =</span><span class="string"> "name2"</span><span class="operator">;</span> d2<span class="operator">-&gt;</span>desc<span class="operator"> =</span><span class="string"> "desc2"</span><span class="operator">;</span>
drug_ptr d3<span class="operator">;</span> d3<span class="operator">.</span>reset<span class="operator">(</span><span class="keyword">new</span> drug<span class="operator">());</span> d3<span class="operator">-&gt;</span>code<span class="operator"> =</span><span class="string"> "code3"</span><span class="operator">;</span> d3<span class="operator">-&gt;</span>name<span class="operator"> =</span><span class="string"> "name3"</span><span class="operator">;</span> d3<span class="operator">-&gt;</span>desc<span class="operator"> =</span><span class="string"> "desc3"</span><span class="operator">;</span><span class="comment">
/* insertion des 3 drugs dans la collection */</span>
lstDrugs<span class="operator">.</span>insert<span class="operator">(</span>d1<span class="operator">-&gt;</span>code<span class="operator">,</span> d1<span class="operator">);</span>
lstDrugs<span class="operator">.</span>insert<span class="operator">(</span>d2<span class="operator">-&gt;</span>code<span class="operator">,</span> d2<span class="operator">);</span>
lstDrugs<span class="operator">.</span>insert<span class="operator">(</span>d3<span class="operator">-&gt;</span>code<span class="operator">,</span> d3<span class="operator">);</span><span class="comment">
/* parcours la collection en utilisant le mot-cl<63> '_foreach' */</span>
_foreach<span class="operator">(</span>drug_ptr p<span class="operator">,</span> lstDrugs<span class="operator">)
{</span> qDebug<span class="operator">() &lt;&lt;</span> qPrintable<span class="operator">(</span>p<span class="operator">-&gt;</span>name<span class="operator">) &lt;&lt;</span><span class="string"> " "</span><span class="operator"> &lt;&lt;</span> qPrintable<span class="operator">(</span>p<span class="operator">-&gt;</span>desc<span class="operator">); }</span><span class="comment">
/* parcours la collection en utilisant une boucle 'for' */</span><span class="flow">
for</span><span class="operator"> (</span><span class="type">long</span> l<span class="operator"> =</span><span class="int"> 0</span><span class="operator">;</span> l<span class="operator"> &lt;</span> lstDrugs<span class="operator">.</span>count<span class="operator">(); ++</span>l<span class="operator">)
{</span>
drug_ptr p<span class="operator"> =</span> lstDrugs<span class="operator">.</span>getByIndex<span class="operator">(</span>l<span class="operator">);</span>
QString code<span class="operator"> =</span> lstDrugs<span class="operator">.</span>getKeyByIndex<span class="operator">(</span>l<span class="operator">);</span>
qDebug<span class="operator">() &lt;&lt;</span> qPrintable<span class="operator">(</span>p<span class="operator">-&gt;</span>name<span class="operator">) &lt;&lt;</span><span class="string"> " "</span><span class="operator"> &lt;&lt;</span> qPrintable<span class="operator">(</span>p<span class="operator">-&gt;</span>desc<span class="operator">);
}</span><span class="comment">
/* parcours la collection en utilisant le style Java avec 'QxCollectionIterator' */</span>
qx<span class="operator">::</span>QxCollectionIterator<span class="operator">&lt;</span>QString<span class="operator">,</span> drug_ptr<span class="operator">&gt;</span> itr<span class="operator">(</span>lstDrugs<span class="operator">);</span><span class="flow">
while</span><span class="operator"> (</span>itr<span class="operator">.</span>next<span class="operator">())
{</span>
QString code<span class="operator"> =</span> itr<span class="operator">.</span>key<span class="operator">();</span>
qDebug<span class="operator">() &lt;&lt;</span> qPrintable<span class="operator">(</span>itr<span class="operator">.</span>value<span class="operator">()-&gt;</span>name<span class="operator">) &lt;&lt;</span><span class="string"> " "</span><span class="operator"> &lt;&lt;</span> qPrintable<span class="operator">(</span>itr<span class="operator">.</span>value<span class="operator">()-&gt;</span>desc<span class="operator">);
}</span><span class="comment">
/* effectue un tri croissant par cl<63> (propri<72>t<EFBFBD> 'code') et d<>croissant par valeur */</span>
lstDrugs<span class="operator">.</span>sortByKey<span class="operator">(</span><span class="bool">true</span><span class="operator">);</span>
lstDrugs<span class="operator">.</span>sortByValue<span class="operator">(</span><span class="bool">false</span><span class="operator">);</span><span class="comment">
/* acc<63>s rapide <20> un drug par son 'code' */</span>
drug_ptr p<span class="operator"> =</span> lstDrugs<span class="operator">.</span>getByKey<span class="operator">(</span><span class="string">"code2"</span><span class="operator">);</span><span class="comment">
/* acc<63>s rapide <20> un drug par son index (position) dans la collection */</span>
drug_ptr p<span class="operator"> =</span> lstDrugs<span class="operator">.</span>getByIndex<span class="operator">(</span><span class="int">2</span><span class="operator">);</span><span class="comment">
/* teste si un drug existe dans la collection et si la liste est vide */</span><span class="type">
bool</span> bExist<span class="operator"> =</span> lstDrugs<span class="operator">.</span>exist<span class="operator">(</span><span class="string">"code3"</span><span class="operator">);</span><span class="type">
bool</span> bEmpty<span class="operator"> =</span> lstDrugs<span class="operator">.</span>empty<span class="operator">();</span><span class="comment">
/* supprime de la collection le 2<>me <20>l<EFBFBD>ment */</span>
lstDrugs<span class="operator">.</span>removeByIndex<span class="operator">(</span><span class="int">2</span><span class="operator">);</span><span class="comment">
/* supprime de la collection l'<27>l<EFBFBD>ment avec le code 'code3' */</span>
lstDrugs<span class="operator">.</span>removeByKey<span class="operator">(</span><span class="string">"code3"</span><span class="operator">);</span><span class="comment">
/* efface tous les <20>l<EFBFBD>ments de la collection */</span>
lstDrugs<span class="operator">.</span>clear<span class="operator">();</span></pre>
</td>
</tr>
</tbody>
</table>
</td>
</tr>
</tbody>
</table>
<br><br>
<a name="faq_81"><u><b>Pourquoi QxOrm fournit un nouveau type de pointeur intelligent
<i>qx::dao::ptr&lt;T&gt;</i> ?</b></u></a><br><br>
<table border="0" style="width: 100%" align="center">
<col>
<col>
<tbody>
<tr>
<td valign="middle" width="30"></td>
<td align="justify">
<b>QxOrm</b> est compatible avec les pointeurs intelligents des biblioth<74>ques <b>boost</b> et
<b>Qt</b>.<br>
Le pointeur intelligent d<>velopp<70> par <b>QxOrm</b> est bas<61> sur <i>QSharedPointer</i> et apporte de
nouvelles fonctionnalit<69>s s'il est utilis<69> avec les fonctions '<i>qx::dao::...</i>'.<br>
<i><a href="../doxygen/html/classqx_1_1dao_1_1ptr.html" target="_blank">qx::dao::ptr&lt;T&gt;</a></i>
conserve automatiquement les valeurs issues de la base de donn<6E>es.<br>
Il est ainsi possible de v<>rifier <20> tout moment si une instance d'objet a subi des modifications gr<67>ce
<20> la m<>thode '<i>isDirty()</i>' : cette m<>thode peut renvoyer la liste de toutes les propri<72>t<EFBFBD>s ayant
<20>t<EFBFBD> modifi<66>es.<br>
<i>qx::dao::ptr&lt;T&gt;</i> peut <20>galement <20>tre utilis<69> par la fonction
'<i>qx::dao::update_optimized()</i>' pour mettre <20> jour en base de donn<6E>es uniquement les champs
modifi<66>s.<br>
<i>qx::dao::ptr&lt;T&gt;</i> peut <20>tre utilis<69> avec un objet simple ou bien avec la plupart des
containers : <i>stl</i>, <i>boost</i>, <i>Qt</i> et <i>qx::QxCollection&lt;Key, Value&gt;</i>.<br>
<br>
<b>Exemple d'utilisation du pointeur intelligent <i>qx::dao::ptr&lt;T&gt;</i> :</b><br>
<br>
<table border="1" bgcolor="#FFFFFF">
<col>
<tbody>
<tr>
<td>
<pre><span class="comment">// exemple d'utilisation de la m<>thode 'isDirty()'
</span>qx<span class="operator">::</span>dao<span class="operator">::</span>ptr<span class="operator">&lt;</span>blog<span class="operator">&gt;</span> blog_isdirty<span class="operator"> =</span> qx<span class="operator">::</span>dao<span class="operator">::</span>ptr<span class="operator">&lt;</span>blog<span class="operator">&gt;(</span><span class="keyword">new</span> blog<span class="operator">());</span>
blog_isdirty<span class="operator">-&gt;</span>m_id<span class="operator"> =</span> blog_1<span class="operator">-&gt;</span>m_id<span class="operator">;</span>
daoError<span class="operator"> =</span> qx<span class="operator">::</span>dao<span class="operator">::</span>fetch_by_id<span class="operator">(</span>blog_isdirty<span class="operator">);</span>
qAssert<span class="operator">(!</span> daoError<span class="operator">.</span>isValid<span class="operator">() &amp;&amp; !</span> blog_isdirty<span class="operator">.</span>isDirty<span class="operator">());</span>
blog_isdirty<span class="operator">-&gt;</span>m_text<span class="operator"> =</span><span class="string"> "blog property 'text' modified =&gt; blog is dirty !!!"</span><span class="operator">;</span>
QStringList lstDiff<span class="operator">;</span><span class="type"> bool</span> bDirty<span class="operator"> =</span> blog_isdirty<span class="operator">.</span>isDirty<span class="operator">(</span>lstDiff<span class="operator">);</span>
qAssert<span class="operator">(</span>bDirty<span class="operator"> &amp;&amp; (</span>lstDiff<span class="operator">.</span>count<span class="operator">() ==</span><span class="int"> 1</span><span class="operator">) &amp;&amp; (</span>lstDiff<span class="operator">.</span>at<span class="operator">(</span><span class="int">0</span><span class="operator">) ==</span><span class="string"> "blog_text"</span><span class="operator">));</span><span class="flow">
if</span><span class="operator"> (</span>bDirty<span class="operator">) {</span> qDebug<span class="operator">(</span><span class="string">"[QxOrm] test dirty 1 : blog is dirty =&gt; '%s'"</span><span class="operator">,</span> qPrintable<span class="operator">(</span>lstDiff<span class="operator">.</span>join<span class="operator">(</span><span class="string">"|"</span><span class="operator">))); }</span><span class="comment">
// met <20> jour uniquement la propri<72>t<EFBFBD> 'm_text' de l'instance 'blog_isdirty'
</span>daoError<span class="operator"> =</span> qx<span class="operator">::</span>dao<span class="operator">::</span>update_optimized<span class="operator">(</span>blog_isdirty<span class="operator">);</span>
qAssert<span class="operator">(!</span> daoError<span class="operator">.</span>isValid<span class="operator">() &amp;&amp; !</span> blog_isdirty<span class="operator">.</span>isDirty<span class="operator">());</span>
qx<span class="operator">::</span>dump<span class="operator">(</span>blog_isdirty<span class="operator">);</span><span class="comment">
// exemple d'utilisation de la m<>thode 'isDirty()' avec une liste d'objets
</span><span class="keyword">typedef</span> qx<span class="operator">::</span>dao<span class="operator">::</span>ptr<span class="operator">&lt;</span> QList<span class="operator">&lt;</span>author_ptr<span class="operator">&gt; &gt;</span> type_lst_author_test_is_dirty<span class="operator">;</span>
type_lst_author_test_is_dirty container_isdirty<span class="operator"> =</span> type_lst_author_test_is_dirty<span class="operator">(</span><span class="keyword">new</span> QList<span class="operator">&lt;</span>author_ptr<span class="operator">&gt;());</span>
daoError<span class="operator"> =</span> qx<span class="operator">::</span>dao<span class="operator">::</span>fetch_all<span class="operator">(</span>container_isdirty<span class="operator">);</span>
qAssert<span class="operator">(!</span> daoError<span class="operator">.</span>isValid<span class="operator">() &amp;&amp; !</span> container_isdirty<span class="operator">.</span>isDirty<span class="operator">() &amp;&amp; (</span>container_isdirty<span class="operator">-&gt;</span>count<span class="operator">() ==</span><span class="int"> 3</span><span class="operator">));</span>
author_ptr author_ptr_dirty<span class="operator"> =</span> container_isdirty<span class="operator">-&gt;</span>at<span class="operator">(</span><span class="int">1</span><span class="operator">);</span>
author_ptr_dirty<span class="operator">-&gt;</span>m_name<span class="operator"> =</span><span class="string"> "author name modified at index 1 =&gt; container is dirty !!!"</span><span class="operator">;</span>
bDirty<span class="operator"> =</span> container_isdirty<span class="operator">.</span>isDirty<span class="operator">(</span>lstDiff<span class="operator">);</span>
qAssert<span class="operator">(</span>bDirty<span class="operator"> &amp;&amp; (</span>lstDiff<span class="operator">.</span>count<span class="operator">() ==</span><span class="int"> 1</span><span class="operator">));</span><span class="flow">
if</span><span class="operator"> (</span>bDirty<span class="operator">) {</span> qDebug<span class="operator">(</span><span class="string">"[QxOrm] test dirty 2 : container is dirty =&gt; '%s'"</span><span class="operator">,</span> qPrintable<span class="operator">(</span>lstDiff<span class="operator">.</span>join<span class="operator">(</span><span class="string">"|"</span><span class="operator">))); }</span>
author_ptr_dirty<span class="operator"> =</span> container_isdirty<span class="operator">-&gt;</span>at<span class="operator">(</span><span class="int">2</span><span class="operator">);</span>
author_ptr_dirty<span class="operator">-&gt;</span>m_birthdate<span class="operator"> =</span> QDate<span class="operator">(</span><span class="int">1998</span><span class="operator">,</span><span class="int"> 03</span><span class="operator">,</span><span class="int"> 06</span><span class="operator">);</span>
bDirty<span class="operator"> =</span> container_isdirty<span class="operator">.</span>isDirty<span class="operator">(</span>lstDiff<span class="operator">);</span>
qAssert<span class="operator">(</span>bDirty<span class="operator"> &amp;&amp; (</span>lstDiff<span class="operator">.</span>count<span class="operator">() ==</span><span class="int"> 2</span><span class="operator">));</span><span class="flow">
if</span><span class="operator"> (</span>bDirty<span class="operator">) {</span> qDebug<span class="operator">(</span><span class="string">"[QxOrm] test dirty 3 : container is dirty =&gt; '%s'"</span><span class="operator">,</span> qPrintable<span class="operator">(</span>lstDiff<span class="operator">.</span>join<span class="operator">(</span><span class="string">"|"</span><span class="operator">))); }</span><span class="comment">
// met <20> jour la propri<72>t<EFBFBD> 'm_name' en position 1, la propri<72>t<EFBFBD> 'm_birthdate' en position 2 et ne change rien en position 0
</span>daoError<span class="operator"> =</span> qx<span class="operator">::</span>dao<span class="operator">::</span>update_optimized<span class="operator">(</span>container_isdirty<span class="operator">);</span>
qAssert<span class="operator">(!</span> daoError<span class="operator">.</span>isValid<span class="operator">() &amp;&amp; !</span> container_isdirty<span class="operator">.</span>isDirty<span class="operator">());</span>
qx<span class="operator">::</span>dump<span class="operator">(</span>container_isdirty<span class="operator">);</span><span class="comment">
// r<>cup<75>re uniquement la propri<72>t<EFBFBD> 'm_dt_creation' du blog
</span>QStringList lstColumns<span class="operator"> =</span> QStringList<span class="operator">() &lt;&lt;</span><span class="string"> "date_creation"</span><span class="operator">;</span>
list_blog lst_blog_with_only_date_creation<span class="operator">;</span>
daoError<span class="operator"> =</span> qx<span class="operator">::</span>dao<span class="operator">::</span>fetch_all<span class="operator">(</span>lst_blog_with_only_date_creation<span class="operator">,</span> NULL<span class="operator">,</span> lstColumns<span class="operator">);</span>
qAssert<span class="operator">(!</span> daoError<span class="operator">.</span>isValid<span class="operator">() &amp;&amp; (</span>lst_blog_with_only_date_creation<span class="operator">.</span>size<span class="operator">() &gt;</span><span class="int"> 0</span><span class="operator">));</span><span class="flow">
if</span><span class="operator"> ((</span>lst_blog_with_only_date_creation<span class="operator">.</span>size<span class="operator">() &gt;</span><span class="int"> 0</span><span class="operator">) &amp;&amp; (</span>lst_blog_with_only_date_creation<span class="operator">[</span><span class="int">0</span><span class="operator">] !=</span> NULL<span class="operator">))
{</span> qAssert<span class="operator">(</span>lst_blog_with_only_date_creation<span class="operator">[</span><span class="int">0</span><span class="operator">]-&gt;</span>m_text<span class="operator">.</span>isEmpty<span class="operator">()); }</span>
qx<span class="operator">::</span>dump<span class="operator">(</span>lst_blog_with_only_date_creation<span class="operator">);</span></pre>
</td>
</tr>
</tbody>
</table>
</td>
</tr>
</tbody>
</table>
<br><br>
<a name="faq_90"><u><b>Faut-il utiliser <i>QString</i> ou <i>std::string</i> ?</b></u></a><br><br>
<table border="0" style="width: 100%" align="center">
<col>
<col>
<tbody>
<tr>
<td valign="middle" width="30"></td>
<td align="justify">
<b>QxOrm</b> conseille d'utiliser la classe <a href="http://doc.qt.io/qt-5/QString.html"
target="_blank"><i>QString</i></a> pour la gestion des cha<68>nes de caract<63>res.<br>
M<>me si <b>boost</b> fournit de nombreuses fonctionnalit<69>s avec son module <a
href="http://www.boost.org/doc/libs/release/doc/html/string_algo.html"
target="_blank"><i>boost::string_algo</i></a>,
la classe <i>QString</i> est plus simple <20> utiliser et surtout prend en charge automatiquement les
diff<66>rents formats : <i>Ascii, Utf8, Utf16, etc.</i><br>
Cependant, <b>QxOrm</b> est compatible avec <i>std::string</i> et <i>std::wstring</i> si vous pr<70>f<EFBFBD>rez
utiliser ce type de cha<68>ne de caract<63>res.
</td>
</tr>
</tbody>
</table>
<br><br>
<a name="faq_95"><u><b>Faut-il utiliser les pointeurs intelligents <i>smart-pointer</i> ?</b></u></a><br><br>
<table border="0" style="width: 100%" align="center">
<col>
<col>
<tbody>
<tr>
<td valign="middle" width="30"></td>
<td align="justify">
<b>QxOrm</b> conseille fortement d'utiliser les pointeurs intelligents de <b>boost</b> ou
<b>Qt</b>.<br>
Le langage C++ ne poss<73>de pas de <i>Garbage Collector</i> comme <i>Java</i> ou <i>C#</i> par
exemple.<br>
L'utilisation des <i>smart-pointer</i> simplifie <20>norm<72>ment la gestion de la m<>moire en C++.<br>
L'id<69>al dans un programme C++ est de n'avoir aucun appel <20> <i>delete</i> ou <i>delete[]</i>.<br>
De plus, les <i>smart-pointer</i> font partie de la nouvelle norme C++ : <b>C++1x</b>.<br>
Il est donc essentiel aujourd'hui de conna<6E>tre les classes suivantes :
<ul>
<li><a href="http://www.boost.org/doc/libs/release/libs/smart_ptr/smart_ptr.htm"
target="_blank"><i>shared_ptr</i>, <i>scoped_ptr</i> et <i>weak_ptr</i></a> pour les pointeurs
intelligents de la biblioth<74>que <b>boost</b> ;
</li>
<li><a href="http://doc-snapshots.qt.io/4.8/qsharedpointer.html"
target="_blank"><i>QSharedPointer</i>, <i>QScopedPointer</i> et <i>QWeakPointer</i></a> pour les
pointeurs intelligents de la biblioth<74>que <b>Qt</b>.
</li>
</ul>
</td>
</tr>
</tbody>
</table>
<br><br>
<a name="faq_100"><u><b>La cl<63> primaire est de type <i>long</i> par d<>faut. Est-il possible d'utiliser une cl<63>
de type <i>QString</i> ou autre ?</b></u></a><br><br>
<table border="0" style="width: 100%" align="center">
<col>
<col>
<tbody>
<tr>
<td valign="middle" width="30"></td>
<td align="justify">
Par d<>faut, lorsqu'un mapping d'une classe C++ est <20>crit avec la m<>thode <i>void
qx::register_class&lt;T&gt;</i>, l'identifiant associ<63> <20> la classe est de type <i>long</i> (cl<63>
primaire avec auto-incr<63>mentation dans la base de donn<6E>es).<br>
<br>
Il est possible de d<>finir un identifiant d'un autre type en utilisant la macro
<b>QX_REGISTER_PRIMARY_KEY</b>.<br>
Cette macro sp<73>cialise le template <i>qx::trait::get_primary_key</i> pour associer un type
d'identifiant <20> une classe C++.<br>
<br>
Par exemple, pour d<>finir un identifiant unique de type <i>QString</i> pour la classe C++
<i>myClass</i> (mapp<70>e vers une table de la BDD avec une colonne de type <i>VARCHAR</i> pour cl<63>
primaire), il suffit d'<27>crire :<br>
<i><b>QX_REGISTER_PRIMARY_KEY(myClass, QString)</b></i><br>
<br>
Voici un exemple d'utilisation de la macro <b>QX_REGISTER_PRIMARY_KEY</b> avec une classe
<i>author</i> poss<73>dant un identifiant de type <i>QString</i> :<br>
<br>
<table border="1" bgcolor="#FFFFFF">
<col>
<tbody>
<tr>
<td>
<pre><span class="pre">#ifndef _QX_BLOG_AUTHOR_H_
#define _QX_BLOG_AUTHOR_H_
</span><span class="keyword">
class</span> author<span class="operator">
{</span><span class="keyword">
public</span><span class="operator">:</span><span class="comment">
// -- propri<72>t<EFBFBD>s
</span> QString m_id<span class="operator">;</span>
QString m_name<span class="operator">;</span><span class="comment">
// -- constructeur, destructeur virtuel
</span> author<span class="operator">() { ; }</span><span class="keyword">
virtual</span><span class="operator"> ~</span>author<span class="operator">() { ; }
};</span>
QX_REGISTER_PRIMARY_KEY<span class="operator">(</span>author<span class="operator">,</span> QString<span class="operator">)</span>
QX_REGISTER_HPP_QX_BLOG<span class="operator">(</span>author<span class="operator">,</span> qx<span class="operator">::</span>trait<span class="operator">::</span>no_base_class_defined<span class="operator">,</span><span class="int"> 0</span><span class="operator">)</span><span class="pre">
#endif // _QX_BLOG_AUTHOR_H_</span></pre>
</td>
</tr>
</tbody>
</table>
</td>
</tr>
</tbody>
</table>
<br><br>
<a name="faq_101"><u><b>Comment d<>finir une cl<63> primaire sur plusieurs colonnes (<i>composite key</i>)
?</b></u></a><br><br>
<table border="0" style="width: 100%" align="center">
<col>
<col>
<tbody>
<tr>
<td valign="middle" width="30"></td>
<td align="justify">
<b>QxOrm</b> supporte la notion de '<i>multi-columns primary key</i>'.<br>
L'identifiant de la classe doit <20>tre du type suivant :
<ul>
<li><i>QPair</i> ou <i>std::pair</i> pour d<>finir deux colonnes ;
</li>
<li><i>boost::tuple</i> pour d<>finir de deux <20> neuf colonnes.
</li>
</ul>
Il est n<>cessaire d'utiliser la macro <b><i>QX_REGISTER_PRIMARY_KEY()</i></b> pour sp<73>cialiser le
template et ainsi d<>finir le type d'identifiant sur plusieurs colonnes.<br>
La liste des noms des colonnes doit <20>tre de la forme suivante :
'<i>column1|column2|column3|etc.</i>'.<br>
<br>
<b>Exemple d'utilisation</b> avec la classe '<i>author</i>' du projet '<i>qxBlogCompositeKey</i>',
cette classe poss<73>de un identifiant sur trois colonnes :<br>
<br>
<table border="1" bgcolor="#FFFFFF">
<col>
<tbody>
<tr>
<td>
<pre><span class="pre">#ifndef _QX_BLOG_AUTHOR_H_
#define _QX_BLOG_AUTHOR_H_
</span><span class="keyword">
class</span> blog<span class="operator">;</span><span class="keyword">
class</span> QX_BLOG_DLL_EXPORT author<span class="operator">
{</span>
QX_REGISTER_FRIEND_CLASS<span class="operator">(</span>author<span class="operator">)</span><span class="keyword">
public</span><span class="operator">:</span><span class="comment">
// -- cl<63> compos<6F>e (cl<63> primaire d<>finie sur plusieurs colonnes dans la base de donn<6E>es)
</span><span class="keyword"> typedef</span> boost<span class="operator">::</span>tuple<span class="operator">&lt;</span>QString<span class="operator">,</span><span class="type"> long</span><span class="operator">,</span> QString<span class="operator">&gt;</span> type_composite_key<span class="operator">;</span><span class="keyword">
static</span> QString str_composite_key<span class="operator">() {</span><span class="flow"> return</span><span class="string"> "author_id_0|author_id_1|author_id_2"</span><span class="operator">; }</span><span class="comment">
// -- typedef
</span><span class="keyword"> typedef</span> boost<span class="operator">::</span>shared_ptr<span class="operator">&lt;</span>blog<span class="operator">&gt;</span> blog_ptr<span class="operator">;</span><span class="keyword">
typedef</span> std<span class="operator">::</span>vector<span class="operator">&lt;</span>blog_ptr<span class="operator">&gt;</span> list_blog<span class="operator">;</span><span class="comment">
// -- enum
</span><span class="keyword"> enum</span> enum_sex<span class="operator"> {</span> male<span class="operator">,</span> female<span class="operator">,</span> unknown<span class="operator"> };</span><span class="comment">
// -- propri<72>t<EFBFBD>s
</span> type_composite_key m_id<span class="operator">;</span>
QString m_name<span class="operator">;</span>
QDate m_birthdate<span class="operator">;</span>
enum_sex m_sex<span class="operator">;</span>
list_blog m_blogX<span class="operator">;</span><span class="comment">
// -- constructeur, destructeur virtuel
</span> author<span class="operator">() :</span> m_id<span class="operator">(</span><span class="string">""</span><span class="operator">,</span><span class="int"> 0</span><span class="operator">,</span><span class="string"> ""</span><span class="operator">),</span> m_sex<span class="operator">(</span>unknown<span class="operator">) { ; }</span><span class="keyword">
virtual</span><span class="operator"> ~</span>author<span class="operator">() { ; }</span><span class="comment">
// -- m<>thodes
</span><span class="type"> int</span> age<span class="operator">()</span><span class="keyword"> const</span><span class="operator">;</span><span class="comment">
// -- m<>thodes d'acc<63>s <20> la cl<63> compos<6F>e
</span> type_composite_key getId<span class="operator">()</span><span class="keyword"> const</span><span class="operator"> {</span><span class="flow"> return</span> m_id<span class="operator">; }</span>
QString getId_0<span class="operator">()</span><span class="keyword"> const</span><span class="operator"> {</span><span class="flow"> return</span> boost<span class="operator">::</span>tuples<span class="operator">::</span>get<span class="operator">&lt;</span><span class="int">0</span><span class="operator">&gt;(</span>m_id<span class="operator">); }</span><span class="type">
long</span> getId_1<span class="operator">()</span><span class="keyword"> const</span><span class="operator"> {</span><span class="flow"> return</span> boost<span class="operator">::</span>tuples<span class="operator">::</span>get<span class="operator">&lt;</span><span class="int">1</span><span class="operator">&gt;(</span>m_id<span class="operator">); }</span>
QString getId_2<span class="operator">()</span><span class="keyword"> const</span><span class="operator"> {</span><span class="flow"> return</span> boost<span class="operator">::</span>tuples<span class="operator">::</span>get<span class="operator">&lt;</span><span class="int">2</span><span class="operator">&gt;(</span>m_id<span class="operator">); }</span><span class="comment">
// -- m<>thodes de modification de la cl<63> compos<6F>e
</span><span class="type"> void</span> setId_0<span class="operator">(</span><span class="keyword">const</span> QString<span class="operator"> &amp;</span> s<span class="operator">) {</span> boost<span class="operator">::</span>tuples<span class="operator">::</span>get<span class="operator">&lt;</span><span class="int">0</span><span class="operator">&gt;(</span>m_id<span class="operator">) =</span> s<span class="operator">; }</span><span class="type">
void</span> setId_1<span class="operator">(</span><span class="type">long</span> l<span class="operator">) {</span> boost<span class="operator">::</span>tuples<span class="operator">::</span>get<span class="operator">&lt;</span><span class="int">1</span><span class="operator">&gt;(</span>m_id<span class="operator">) =</span> l<span class="operator">; }</span><span class="type">
void</span> setId_2<span class="operator">(</span><span class="keyword">const</span> QString<span class="operator"> &amp;</span> s<span class="operator">) {</span> boost<span class="operator">::</span>tuples<span class="operator">::</span>get<span class="operator">&lt;</span><span class="int">2</span><span class="operator">&gt;(</span>m_id<span class="operator">) =</span> s<span class="operator">; }
};</span>
QX_REGISTER_PRIMARY_KEY<span class="operator">(</span>author<span class="operator">,</span> author<span class="operator">::</span>type_composite_key<span class="operator">)</span>
QX_REGISTER_HPP_QX_BLOG<span class="operator">(</span>author<span class="operator">,</span> qx<span class="operator">::</span>trait<span class="operator">::</span>no_base_class_defined<span class="operator">,</span><span class="int"> 0</span><span class="operator">)</span><span class="keyword">
typedef</span> boost<span class="operator">::</span>shared_ptr<span class="operator">&lt;</span>author<span class="operator">&gt;</span> author_ptr<span class="operator">;</span><span class="keyword">
typedef</span> qx<span class="operator">::</span>QxCollection<span class="operator">&lt;</span>author<span class="operator">::</span>type_composite_key<span class="operator">,</span> author_ptr<span class="operator">&gt;</span> list_author<span class="operator">;</span><span class="pre">
#endif // _QX_BLOG_AUTHOR_H_
</span></pre>
</td>
</tr>
</tbody>
</table>
<br>
<table border="1" bgcolor="#FFFFFF">
<col>
<tbody>
<tr>
<td>
<pre><span class="pre">#include "../include/precompiled.h"
#include "../include/author.h"
#include "../include/blog.h"
#include &lt;QxOrm_Impl.h&gt;
</span>
QX_REGISTER_CPP_QX_BLOG<span class="operator">(</span>author<span class="operator">)</span><span class="keyword">
namespace</span> qx<span class="operator"> {</span><span class="keyword">
template</span><span class="operator"> &lt;&gt;</span><span class="type"> void</span> register_class<span class="operator">(</span>QxClass<span class="operator">&lt;</span>author<span class="operator">&gt; &amp;</span> t<span class="operator">)
{</span>
t<span class="operator">.</span>id<span class="operator">(&amp;</span> author<span class="operator">::</span>m_id<span class="operator">,</span> author<span class="operator">::</span>str_composite_key<span class="operator">());</span>
t<span class="operator">.</span>data<span class="operator">(&amp;</span> author<span class="operator">::</span>m_name<span class="operator">,</span><span class="string"> "name"</span><span class="operator">);</span>
t<span class="operator">.</span>data<span class="operator">(&amp;</span> author<span class="operator">::</span>m_birthdate<span class="operator">,</span><span class="string"> "birthdate"</span><span class="operator">);</span>
t<span class="operator">.</span>data<span class="operator">(&amp;</span> author<span class="operator">::</span>m_sex<span class="operator">,</span><span class="string"> "sex"</span><span class="operator">);</span>
t<span class="operator">.</span>relationOneToMany<span class="operator">(&amp;</span> author<span class="operator">::</span>m_blogX<span class="operator">,</span> blog<span class="operator">::</span>str_composite_key<span class="operator">(),</span> author<span class="operator">::</span>str_composite_key<span class="operator">());</span>
t<span class="operator">.</span>fct_0<span class="operator">&lt;</span><span class="type">int</span><span class="operator">&gt;(&amp;</span> author<span class="operator">::</span>age<span class="operator">,</span><span class="string"> "age"</span><span class="operator">);
}}</span><span class="type">
int</span> author<span class="operator">::</span>age<span class="operator">()</span><span class="keyword"> const</span><span class="operator">
{</span><span class="flow">
if</span><span class="operator"> (!</span> m_birthdate<span class="operator">.</span>isValid<span class="operator">()) {</span><span class="flow"> return</span><span class="operator"> -</span><span class="int">1</span><span class="operator">; }</span><span class="flow">
return</span><span class="operator"> (</span>QDate<span class="operator">::</span>currentDate<span class="operator">().</span>year<span class="operator">() -</span> m_birthdate<span class="operator">.</span>year<span class="operator">());
}</span>
</pre>
</td>
</tr>
</tbody>
</table>
</td>
</tr>
</tbody>
</table>
<br><br>
<a name="faq_105"><u><b>Comment enregistrer des membres <i>private</i> ou <i>protected</i> dans le contexte
QxOrm ?</b></u></a><br><br>
<table border="0" style="width: 100%" align="center">
<col>
<col>
<tbody>
<tr>
<td valign="middle" width="30"></td>
<td align="justify">
Pour enregistrer des membres <i>private</i> ou <i>protected</i> dans le contexte QxOrm (fonction
<i>qx::register_class&lt;T&gt;</i>), il faut d<>clarer les <i>friend class</i> n<>cessaires.<br>
Pour simplifier l'<27>criture avec les <i>template</i> C++, la biblioth<74>que QxOrm fournit la macro
suivante : <b>QX_REGISTER_FRIEND_CLASS(myClass)</b>.<br>
Un exemple d'utilisation se trouve dans le dossier <i>./test/qxDllSample/dll1/</i> du package QxOrm
avec la classe <i>CPerson</i> :<br>
<br>
<table border="1" bgcolor="#FFFFFF">
<col>
<tbody>
<tr>
<td>
<pre><span class="keyword">namespace</span> qx<span class="operator"> {</span><span class="keyword">
namespace</span> test<span class="operator"> {</span><span class="keyword">
class</span> QX_DLL1_EXPORT CPerson<span class="operator"> :</span><span class="keyword"> public</span> QObject<span class="operator">
{</span>
Q_OBJECT
<font style="background-color:yellow">QX_REGISTER_FRIEND_CLASS<span class="operator">(</span>qx<span class="operator">::</span>test<span class="operator">::</span>CPerson<span class="operator">)</span></font><span class="comment">
// etc...
</span><span class="operator">
};
}</span><span class="comment"> // namespace test
</span><span class="operator">}</span><span class="comment"> // namespace qx</span></pre>
</td>
</tr>
</tbody>
</table>
<br>
</td>
</tr>
</tbody>
</table>
<br><br>
<a name="faq_110"><u><b>Comment activer/d<>sactiver le module <i>QxMemLeak</i> pour la d<>tection automatique
des fuites m<>moires ?</b></u></a><br><br>
<table border="0" style="width: 100%" align="center">
<col>
<col>
<tbody>
<tr>
<td valign="middle" width="30"></td>
<td align="justify">
Le module <i>QxMemLeak</i> permet une d<>tection rapide des fuites
m<>moire en mode <i>Debug</i> une fois l'ex<65>cution du programme termin<69>e
(avec indication du fichier et de la ligne =&gt; style MFC de
Microsoft).<br>
Ce module a <20>t<EFBFBD> d<>velopp<70> par <a href="http://wyw.dcweb.cn/leakage.htm" target="_blank">Wu Yongwei</a>
et a subi
quelques modifications pour <20>tre int<6E>gr<67> dans <b>QxOrm</b>.<br>
Si un autre outil est d<>j<EFBFBD> utilis<69> (<i>Valgrind</i> par exemple),
cette fonctionnalit<69> ne doit pas <20>tre activ<69>e.<br>
Pour activer/d<>sactiver le module <i>QxMemLeak</i>, il suffit de modifier la constante
<b><i>_QX_USE_MEM_LEAK_DETECTION</i></b> d<>finie dans le fichier <i>QxConfig.h</i>.<br>
Une recompilation de la biblioth<74>que QxOrm est n<>cessaire pour prendre en compte cette modification.
</td>
</tr>
</tbody>
</table>
<br><br>
<a name="faq_120"><u><b>Comment g<>rer la notion d'h<>ritage avec la base de donn<6E>es ?</b></u></a><br><br>
<table border="0" style="width: 100%" align="center">
<col>
<col>
<tbody>
<tr>
<td valign="middle" width="30"></td>
<td align="justify">
On retrouve g<>n<EFBFBD>ralement dans les diff<66>rents outils de type <i>ORM</i> trois diff<66>rentes strat<61>gies
pour g<>rer la notion d'h<>ritage avec la base de donn<6E>es :
<ul>
<li><i><a href="http://martinfowler.com/eaaCatalog/singleTableInheritance.html"
target="_blank">Single Table Inheritance</a></i> (une seule table regroupant toutes les
propri<72>t<EFBFBD>s d'une hi<68>rarchie d'h<>ritage de classes) ;
</li>
<li><i><a href="http://martinfowler.com/eaaCatalog/classTableInheritance.html" target="_blank">Class
Table Inheritance</a></i> (<28> chaque classe d'une hi<68>rarchie d'h<>ritage est associ<63>e une table
dans la base de donn<6E>es) ;
</li>
<li><i><a href="http://martinfowler.com/eaaCatalog/concreteTableInheritance.html"
target="_blank">Concrete Table Inheritance</a></i> (une table par classe concr<63>te dans la
hi<68>rarchie d'h<>ritage).
</li>
</ul>
<b>QxOrm</b> utilise par d<>faut la strat<61>gie <i>Concrete Table Inheritance</i> (les autres strat<61>gies
ne sont pas fonctionnelles <20> l'heure actuelle).<br>
De nombreux tutoriaux et forums sont disponibles sur internet pour plus de d<>tails sur cette notion
d'h<>ritage.<br>
Un exemple d'utilisation avec une classe de base se trouve dans le dossier
<i>./test/qxDllSample/dll2/</i> avec la classe <i>BaseClassTrigger</i>.
</td>
</tr>
</tbody>
</table>
<br><br>
<a name="faq_130"><u><b>Comment utiliser les <i>Trigger</i> ?</b></u></a><br><br>
<table border="0" style="width: 100%" align="center">
<col>
<col>
<tbody>
<tr>
<td valign="middle" width="30"></td>
<td align="justify">
Les <i>Trigger</i> de <b>QxOrm</b> permettent d'effectuer divers traitements avant et/ou apr<70>s une
insertion, une mise <20> jour ou bien une suppression dans la base de donn<6E>es.<br>
Un exemple d'utilisation se trouve dans le dossier <i>./test/qxDllSample/dll2/</i> avec la classe
<i>BaseClassTrigger</i>.<br>
Cette classe contient cinq propri<72>t<EFBFBD>s : <i>m_id</i>, <i>m_dateCreation</i>, <i>m_dateModification</i>,
<i>m_userCreation</i> et <i>m_userModification</i>.<br>
Ces propri<72>t<EFBFBD>s se mettront <20> jour automatiquement pour chaque classe h<>ritant de
<i>BaseClassTrigger</i> (cf. les classes <i>Foo</i> et <i>Bar</i> du m<>me projet).<br>
Il est n<>cessaire de sp<73>cialiser le template '<i>QxDao_Trigger</i>' pour profiter de cette
fonctionnalit<69>.<br>
<br>
<table border="1" bgcolor="#FFFFFF">
<col>
<tbody>
<tr>
<td>
<pre><span class="pre">#ifndef _QX_BASE_CLASS_TRIGGER_H_
#define _QX_BASE_CLASS_TRIGGER_H_
</span><span class="keyword">
class</span> QX_DLL2_EXPORT BaseClassTrigger<span class="operator">
{</span>
QX_REGISTER_FRIEND_CLASS<span class="operator">(</span>BaseClassTrigger<span class="operator">)</span><span class="keyword">
protected</span><span class="operator">:</span><span class="type">
long</span> m_id<span class="operator">;</span>
QDateTime m_dateCreation<span class="operator">;</span>
QDateTime m_dateModification<span class="operator">;</span>
QString m_userCreation<span class="operator">;</span>
QString m_userModification<span class="operator">;</span><span class="keyword">
public</span><span class="operator">:</span>
BaseClassTrigger<span class="operator">() :</span> m_id<span class="operator">(</span><span class="int">0</span><span class="operator">) { ; }</span><span class="keyword">
virtual</span><span class="operator"> ~</span>BaseClassTrigger<span class="operator">() { ; }</span><span class="type">
long</span> getId<span class="operator">()</span><span class="keyword"> const</span><span class="operator"> {</span><span class="flow"> return</span> m_id<span class="operator">; }</span>
QDateTime getDateCreation<span class="operator">()</span><span class="keyword"> const</span><span class="operator"> {</span><span class="flow"> return</span> m_dateCreation<span class="operator">; }</span>
QDateTime getDateModification<span class="operator">()</span><span class="keyword"> const</span><span class="operator"> {</span><span class="flow"> return</span> m_dateModification<span class="operator">; }</span>
QString getUserCreation<span class="operator">()</span><span class="keyword"> const</span><span class="operator"> {</span><span class="flow"> return</span> m_userCreation<span class="operator">; }</span>
QString getUserModification<span class="operator">()</span><span class="keyword"> const</span><span class="operator"> {</span><span class="flow"> return</span> m_userModification<span class="operator">; }</span><span class="type">
void</span> setId<span class="operator">(</span><span class="type">long</span> l<span class="operator">) {</span> m_id<span class="operator"> =</span> l<span class="operator">; }</span><span class="type">
void</span> setDateCreation<span class="operator">(</span><span class="keyword">const</span> QDateTime<span class="operator"> &amp;</span> dt<span class="operator">) {</span> m_dateCreation<span class="operator"> =</span> dt<span class="operator">; }</span><span class="type">
void</span> setDateModification<span class="operator">(</span><span class="keyword">const</span> QDateTime<span class="operator"> &amp;</span> dt<span class="operator">) {</span> m_dateModification<span class="operator"> =</span> dt<span class="operator">; }</span><span class="type">
void</span> setUserCreation<span class="operator">(</span><span class="keyword">const</span> QString<span class="operator"> &amp;</span> s<span class="operator">) {</span> m_userCreation<span class="operator"> =</span> s<span class="operator">; }</span><span class="type">
void</span> setUserModification<span class="operator">(</span><span class="keyword">const</span> QString<span class="operator"> &amp;</span> s<span class="operator">) {</span> m_userModification<span class="operator"> =</span> s<span class="operator">; }</span><span class="type">
void</span> onBeforeInsert<span class="operator">(</span>qx<span class="operator">::</span>dao<span class="operator">::</span>detail<span class="operator">::</span>IxDao_Helper<span class="operator"> *</span> dao<span class="operator">);</span><span class="type">
void</span> onBeforeUpdate<span class="operator">(</span>qx<span class="operator">::</span>dao<span class="operator">::</span>detail<span class="operator">::</span>IxDao_Helper<span class="operator"> *</span> dao<span class="operator">);
};</span>
QX_REGISTER_HPP_QX_DLL2<span class="operator">(</span>BaseClassTrigger<span class="operator">,</span> qx<span class="operator">::</span>trait<span class="operator">::</span>no_base_class_defined<span class="operator">,</span><span class="int"> 0</span><span class="operator">)</span><span class="keyword">
namespace</span> qx<span class="operator"> {</span><span class="keyword">
namespace</span> dao<span class="operator"> {</span><span class="keyword">
namespace</span> detail<span class="operator"> {</span><span class="keyword">
template</span><span class="operator"> &lt;&gt;</span><span class="keyword">
struct</span> QxDao_Trigger<span class="operator">&lt;</span>BaseClassTrigger<span class="operator">&gt;
{</span><span class="keyword">
static inline</span><span class="type"> void</span> onBeforeInsert<span class="operator">(</span>BaseClassTrigger<span class="operator"> *</span> t<span class="operator">,</span> qx<span class="operator">::</span>dao<span class="operator">::</span>detail<span class="operator">::</span>IxDao_Helper<span class="operator"> *</span> dao<span class="operator">)
{</span><span class="flow"> if</span><span class="operator"> (</span>t<span class="operator">) {</span> t<span class="operator">-&gt;</span>onBeforeInsert<span class="operator">(</span>dao<span class="operator">); } }</span><span class="keyword">
static inline</span><span class="type"> void</span> onBeforeUpdate<span class="operator">(</span>BaseClassTrigger<span class="operator"> *</span> t<span class="operator">,</span> qx<span class="operator">::</span>dao<span class="operator">::</span>detail<span class="operator">::</span>IxDao_Helper<span class="operator"> *</span> dao<span class="operator">)
{</span><span class="flow"> if</span><span class="operator"> (</span>t<span class="operator">) {</span> t<span class="operator">-&gt;</span>onBeforeUpdate<span class="operator">(</span>dao<span class="operator">); } }</span><span class="keyword">
static inline</span><span class="type"> void</span> onBeforeDelete<span class="operator">(</span>BaseClassTrigger<span class="operator"> *</span> t<span class="operator">,</span> qx<span class="operator">::</span>dao<span class="operator">::</span>detail<span class="operator">::</span>IxDao_Helper<span class="operator"> *</span> dao<span class="operator">)
{</span> Q_UNUSED<span class="operator">(</span>t<span class="operator">);</span> Q_UNUSED<span class="operator">(</span>dao<span class="operator">); }</span><span class="keyword">
static inline</span><span class="type"> void</span> onBeforeFetch<span class="operator">(</span>BaseClassTrigger<span class="operator"> *</span> t<span class="operator">,</span> qx<span class="operator">::</span>dao<span class="operator">::</span>detail<span class="operator">::</span>IxDao_Helper<span class="operator"> *</span> dao<span class="operator">)
{</span> Q_UNUSED<span class="operator">(</span>t<span class="operator">);</span> Q_UNUSED<span class="operator">(</span>dao<span class="operator">); }</span><span class="keyword">
static inline</span><span class="type"> void</span> onAfterInsert<span class="operator">(</span>BaseClassTrigger<span class="operator"> *</span> t<span class="operator">,</span> qx<span class="operator">::</span>dao<span class="operator">::</span>detail<span class="operator">::</span>IxDao_Helper<span class="operator"> *</span> dao<span class="operator">)
{</span> Q_UNUSED<span class="operator">(</span>t<span class="operator">);</span> Q_UNUSED<span class="operator">(</span>dao<span class="operator">); }</span><span class="keyword">
static inline</span><span class="type"> void</span> onAfterUpdate<span class="operator">(</span>BaseClassTrigger<span class="operator"> *</span> t<span class="operator">,</span> qx<span class="operator">::</span>dao<span class="operator">::</span>detail<span class="operator">::</span>IxDao_Helper<span class="operator"> *</span> dao<span class="operator">)
{</span> Q_UNUSED<span class="operator">(</span>t<span class="operator">);</span> Q_UNUSED<span class="operator">(</span>dao<span class="operator">); }</span><span class="keyword">
static inline</span><span class="type"> void</span> onAfterDelete<span class="operator">(</span>BaseClassTrigger<span class="operator"> *</span> t<span class="operator">,</span> qx<span class="operator">::</span>dao<span class="operator">::</span>detail<span class="operator">::</span>IxDao_Helper<span class="operator"> *</span> dao<span class="operator">)
{</span> Q_UNUSED<span class="operator">(</span>t<span class="operator">);</span> Q_UNUSED<span class="operator">(</span>dao<span class="operator">); }
static inline</span><span class="type"> void</span> onAfterFetch<span class="operator">(</span>BaseClassTrigger<span class="operator"> *</span> t<span class="operator">,</span> qx<span class="operator">::</span>dao<span class="operator">::</span>detail<span class="operator">::</span>IxDao_Helper<span class="operator"> *</span> dao<span class="operator">)
{</span> Q_UNUSED<span class="operator">(</span>t<span class="operator">);</span> Q_UNUSED<span class="operator">(</span>dao<span class="operator">); }
};
}</span><span class="comment"> // namespace detail
</span><span class="operator">}</span><span class="comment"> // namespace dao
</span><span class="operator">}</span><span class="comment"> // namespace qx
</span><span class="pre">
#endif // _QX_BASE_CLASS_TRIGGER_H_
</span></pre>
</td>
</tr>
</tbody>
</table>
<br>
<table border="1" bgcolor="#FFFFFF">
<col>
<tbody>
<tr>
<td>
<pre><span class="pre">#include "../include/precompiled.h"
#include "../include/BaseClassTrigger.h"
#include &lt;QxOrm_Impl.h&gt;
</span>
QX_REGISTER_CPP_QX_DLL2<span class="operator">(</span>BaseClassTrigger<span class="operator">)</span><span class="keyword">
namespace</span> qx<span class="operator"> {</span><span class="keyword">
template</span><span class="operator"> &lt;&gt;</span><span class="type"> void</span> register_class<span class="operator">(</span>QxClass<span class="operator">&lt;</span>BaseClassTrigger<span class="operator">&gt; &amp;</span> t<span class="operator">)
{</span>
IxDataMember<span class="operator"> *</span> pData<span class="operator"> =</span> NULL<span class="operator">;</span>
pData<span class="operator"> =</span> t<span class="operator">.</span>id<span class="operator">(&amp;</span> BaseClassTrigger<span class="operator">::</span>m_id<span class="operator">,</span><span class="string"> "id"</span><span class="operator">);</span>
pData<span class="operator"> =</span> t<span class="operator">.</span>data<span class="operator">(&amp;</span> BaseClassTrigger<span class="operator">::</span>m_dateCreation<span class="operator">,</span><span class="string"> "date_creation"</span><span class="operator">);</span>
pData<span class="operator"> =</span> t<span class="operator">.</span>data<span class="operator">(&amp;</span> BaseClassTrigger<span class="operator">::</span>m_dateModification<span class="operator">,</span><span class="string"> "date_modification"</span><span class="operator">);</span>
pData<span class="operator"> =</span> t<span class="operator">.</span>data<span class="operator">(&amp;</span> BaseClassTrigger<span class="operator">::</span>m_userCreation<span class="operator">,</span><span class="string"> "user_creation"</span><span class="operator">);</span>
pData<span class="operator"> =</span> t<span class="operator">.</span>data<span class="operator">(&amp;</span> BaseClassTrigger<span class="operator">::</span>m_userModification<span class="operator">,</span><span class="string"> "user_modification"</span><span class="operator">);
}}</span><span class="type">
void</span> BaseClassTrigger<span class="operator">::</span>onBeforeInsert<span class="operator">(</span>qx<span class="operator">::</span>dao<span class="operator">::</span>detail<span class="operator">::</span>IxDao_Helper<span class="operator"> *</span> dao<span class="operator">)
{</span>
Q_UNUSED<span class="operator">(</span>dao<span class="operator">);</span>
m_dateCreation<span class="operator"> =</span> QDateTime<span class="operator">::</span>currentDateTime<span class="operator">();</span>
m_dateModification<span class="operator"> =</span> QDateTime<span class="operator">::</span>currentDateTime<span class="operator">();</span>
m_userCreation<span class="operator"> =</span><span class="string"> "current_user_1"</span><span class="operator">;</span>
m_userModification<span class="operator"> =</span><span class="string"> "current_user_1"</span><span class="operator">;
}</span><span class="type">
void</span> BaseClassTrigger<span class="operator">::</span>onBeforeUpdate<span class="operator">(</span>qx<span class="operator">::</span>dao<span class="operator">::</span>detail<span class="operator">::</span>IxDao_Helper<span class="operator"> *</span> dao<span class="operator">)
{</span>
Q_UNUSED<span class="operator">(</span>dao<span class="operator">);</span>
m_dateModification<span class="operator"> =</span> QDateTime<span class="operator">::</span>currentDateTime<span class="operator">();</span>
m_userModification<span class="operator"> =</span><span class="string"> "current_user_2"</span><span class="operator">;
}</span>
</pre>
</td>
</tr>
</tbody>
</table>
</td>
</tr>
</tbody>
</table>
<br><br>
<a name="faq_140"><u><b>Comment d<>clarer une classe abstraite dans le contexte QxOrm ?</b></u></a><br><br>
<table border="0" style="width: 100%" align="center">
<col>
<col>
<tbody>
<tr>
<td valign="middle" width="30"></td>
<td align="justify">
Une classe abstraite C++ (contenant au moins une m<>thode virtuelle pure) ne peut pas <20>tre mapp<70>e avec
une table d'une base de donn<6E>es (puisqu'elle ne peut pas <20>tre instanci<63>e).<br>
Cependant, il peut <20>tre int<6E>ressant de d<>finir une classe abstraite contenant une liste de propri<72>t<EFBFBD>s
utilis<69>es par plusieurs objets persistants.<br>
Un exemple de classe abstraite se trouve dans le dossier <i>./test/qxDllSample/dll2/</i> de la
distribution de QxOrm avec la classe <i>BaseClassTrigger</i>.<br>
QxOrm propose le m<>canisme suivant pour d<>finir une classe abstraite dans le contexte QxOrm :
<ul>
<li>d<EFBFBD>clarer la classe avec la m<>thode '<i>void register_class</i>' comme n'importe qu'elle autre
classe ;
</li>
<li>utiliser la macro <b>QX_REGISTER_ABSTRACT_CLASS(className)</b> juste apr<70>s la d<>finition de la
classe.
</li>
</ul>
</td>
</tr>
</tbody>
</table>
<br><br>
<a name="faq_150"><u><b>Comment d<>clarer une classe d<>finie dans un espace de nom (<i>namespace</i>) dans le
contexte QxOrm ?</b></u></a><br><br>
<table border="0" style="width: 100%" align="center">
<col>
<col>
<tbody>
<tr>
<td valign="middle" width="30"></td>
<td align="justify">
Si une classe est d<>finie dans un espace de nom (<i>namespace</i>), alors une erreur de compilation se
produit avec l'utilisation des macros : <b>QX_REGISTER_HPP</b> et <b>QX_REGISTER_CPP</b>.<br>
Pour <20>viter ces erreurs de compilation, il est n<>cessaire d'utiliser les macros suivantes :
<b>QX_REGISTER_COMPLEX_CLASS_NAME_HPP</b> et <b>QX_REGISTER_COMPLEX_CLASS_NAME_CPP</b>.<br>
<br>
Vous trouverez un exemple d'utilisation dans le dossier <i>./test/qxDllSample/dll1/</i> de la
distribution de QxOrm avec la classe <i>CPerson</i> d<>finie dans l'espace de nom <i>qx::test</i> :<br>
* <i><b>QX_REGISTER_COMPLEX_CLASS_NAME_HPP_QX_DLL1(qx::test::CPerson, QObject, 0,
qx_test_CPerson)</b></i><br>
<br>
Les macros <b>QX_REGISTER_COMPLEX_CLASS_NAME...</b> n<>cessitent un param<61>tre suppl<70>mentaire (dans
l'exemple ci-dessus il s'agit du param<61>tre <i>qx_test_CPerson</i>) afin de cr<63>er une variable
globale.<br>
Celle-ci est appel<65>e d<>s le lancement de l'application.<br>
La construction de cette instance globale d<>clare la classe dans le module <i>QxFactory</i> (mod<6F>le de
conception fabrique ou design pattern factory).<br>
Un objet C++ ne pouvant pas se nommer avec des caract<63>res "<i>::</i>", le param<61>tre suppl<70>mentaire de
la macro permet de remplacer tous les "<i>::</i>" par des "<i>_</i>".<br>
</td>
</tr>
</tbody>
</table>
<br><br>
<a name="faq_160"><u><b>Comment utiliser le m<>canisme de suppression logique (<i>soft delete</i>)
?</b></u></a><br><br>
<table border="0" style="width: 100%" align="center">
<col>
<col>
<tbody>
<tr>
<td valign="middle" width="30"></td>
<td align="justify">
Une suppression logique permet de ne pas effacer de ligne dans une table d'une base de donn<6E>es
(contrairement <20> une suppression physique) : une colonne suppl<70>mentaire est ajout<75>e <20> la d<>finition de
la table pour indiquer que la ligne est supprim<69>e ou non.<br>
Cette colonne peut contenir soit un bool<6F>en (1 signifie ligne supprim<69>e, 0 ou vide signifie ligne non
supprim<69>e), soit la date-heure de suppression de la ligne (si vide, la ligne est consid<69>r<EFBFBD>e comme non
supprim<69>e).<br>
Il est donc <20> tout moment possible de r<>activer une ligne supprim<69>e en r<>initialisant la valeur <20> vide
dans la table de la base de donn<6E>es.<br>
<br>
Pour activer le m<>canisme de suppression logique avec la biblioth<74>que QxOrm, il faut utiliser la
classe <b>qx::QxSoftDelete</b> dans la fonction de mapping <i>qx::register_class&lt;T&gt;</i>.<br>
Voici un exemple d'utilisation avec une classe <i>Bar</i> contenant deux propri<72>t<EFBFBD>s <i>m_id</i> et
<i>m_desc</i> :<br>
<br>
<table border="1" bgcolor="#FFFFFF">
<col>
<tbody>
<tr>
<td>
<pre><span class="keyword">namespace</span> qx<span class="operator"> {</span><span class="keyword">
template</span><span class="operator"> &lt;&gt;</span><span class="type"> void</span> register_class<span class="operator">(</span>QxClass<span class="operator">&lt;</span>Bar<span class="operator">&gt; &amp;</span> t<span class="operator">)
{</span>
t<span class="operator">.</span>setSoftDelete<span class="operator">(</span>qx<span class="operator">::</span>QxSoftDelete<span class="operator">(</span><span class="string">"deleted_at"</span><span class="operator">));</span>
t<span class="operator">.</span>id<span class="operator">(&amp;</span> Bar<span class="operator">::</span>m_id<span class="operator">,</span><span class="string"> "id"</span><span class="operator">);</span>
t<span class="operator">.</span>data<span class="operator">(&amp;</span> Bar<span class="operator">::</span>m_desc<span class="operator">,</span><span class="string"> "desc"</span><span class="operator">);
}}</span></pre>
</td>
</tr>
</tbody>
</table>
<br>
Les requ<71>tes SQL g<>n<EFBFBD>r<EFBFBD>es automatiquement par la biblioth<74>que QxOrm vont prendre en compte ce
param<61>tre de suppression logique pour ajouter les conditions n<>cessaires (ne pas r<>cup<75>rer les
<20>l<EFBFBD>ments supprim<69>s, ne pas supprimer physiquement une ligne, etc.).<br>
Par exemple, si vous ex<65>cutez les lignes suivantes avec la classe <i>Bar</i> :<br>
<br>
<table border="1" bgcolor="#FFFFFF">
<col>
<tbody>
<tr>
<td>
<pre>Bar_ptr pBar<span class="operator">;</span> pBar<span class="operator">.</span>reset<span class="operator">(</span><span class="keyword">new</span> Bar<span class="operator">());</span>
pBar<span class="operator">-&gt;</span>setId<span class="operator">(</span><span class="int">5</span><span class="operator">);</span>
QSqlError daoError<span class="operator"> =</span> qx<span class="operator">::</span>dao<span class="operator">::</span>delete_by_id<span class="operator">(</span>pBar<span class="operator">);</span> qAssert<span class="operator">(!</span> daoError<span class="operator">.</span>isValid<span class="operator">());</span>
qx_bool bDaoExist<span class="operator"> =</span> qx<span class="operator">::</span>dao<span class="operator">::</span>exist<span class="operator">(</span>pBar<span class="operator">);</span> qAssert<span class="operator">(!</span> bDaoExist<span class="operator">);</span>
daoError<span class="operator"> =</span> qx<span class="operator">::</span>dao<span class="operator">::</span>delete_all<span class="operator">&lt;</span>Bar<span class="operator">&gt;();</span> qAssert<span class="operator">(!</span> daoError<span class="operator">.</span>isValid<span class="operator">());</span><span class="type">
long</span> lBarCount<span class="operator"> =</span> qx<span class="operator">::</span>dao<span class="operator">::</span>count<span class="operator">&lt;</span>Bar<span class="operator">&gt;();</span> qAssert<span class="operator">(</span>lBarCount<span class="operator"> ==</span><span class="int"> 0</span><span class="operator">);</span>
daoError<span class="operator"> =</span> qx<span class="operator">::</span>dao<span class="operator">::</span>destroy_all<span class="operator">&lt;</span>Bar<span class="operator">&gt;();</span> qAssert<span class="operator">(!</span> daoError<span class="operator">.</span>isValid<span class="operator">());</span></pre>
</td>
</tr>
</tbody>
</table>
<br>
Vous obtiendrez les traces suivantes :<br>
<br>
<table border="1" bgcolor="#FFFFFF">
<col>
<tbody>
<tr>
<td>
<pre><span class="operator">[</span>QxOrm<span class="operator">]</span> sql query<span class="operator"> (</span><span class="int">93</span> ms<span class="operator">) :</span> UPDATE Bar SET deleted_at<span class="operator"> =</span><span class="char"> '20110617115148615'</span> WHERE id<span class="operator"> = :</span>id<span class="operator">
[</span>QxOrm<span class="operator">]</span> sql query<span class="operator"> (</span><span class="int">0</span> ms<span class="operator">) :</span> SELECT Bar<span class="operator">.</span>id AS Bar_id_0<span class="operator">,</span> Bar<span class="operator">.</span>deleted_at FROM Bar WHERE Bar<span class="operator">.</span>id<span class="operator"> = :</span>id AND<span class="operator"> (</span>Bar<span class="operator">.</span>deleted_at IS NULL OR Bar<span class="operator">.</span>deleted_at<span class="operator"> =</span><span class="char"> ''</span><span class="operator">)
[</span>QxOrm<span class="operator">]</span> sql query<span class="operator"> (</span><span class="int">78</span> ms<span class="operator">) :</span> UPDATE Bar SET deleted_at<span class="operator"> =</span><span class="char"> '20110617115148724'</span><span class="operator">
[</span>QxOrm<span class="operator">]</span> sql query<span class="operator"> (</span><span class="int">0</span> ms<span class="operator">) :</span> SELECT COUNT<span class="operator">(*)</span> FROM Bar WHERE<span class="operator"> (</span>Bar<span class="operator">.</span>deleted_at IS NULL OR Bar<span class="operator">.</span>deleted_at<span class="operator"> =</span><span class="char"> ''</span><span class="operator">)
[</span>QxOrm<span class="operator">]</span> sql query<span class="operator"> (</span><span class="int">110</span> ms<span class="operator">) :</span> DELETE FROM Bar</pre>
</td>
</tr>
</tbody>
</table>
<br>
<b>Remarque :</b> pour supprimer physiquement une ligne de la base de donn<6E>es, il faut utiliser les
fonctions : <i>qx::dao::destroy_by_id()</i> et <i>qx::dao::destroy_all()</i>.<br>
<br>
<b>Autre remarque :</b> il peut <20>tre int<6E>ressant de d<>finir au niveau du SGBD un index sur la colonne
<i>deleted_at</i> (ou peu importe le nom que vous donnez) afin d'acc<63>l<EFBFBD>rer l'ex<65>cution des requ<71>tes
SQL.<br>
</td>
</tr>
</tbody>
</table>
<br><br>
<a name="faq_170"><u><b>Comment utiliser les sessions (classe <i>qx::QxSession</i>) pour simplifier la gestion
des transactions des bases de donn<6E>es (C++ RAII) ?</b></u></a><br><br>
<table border="0" style="width: 100%" align="center">
<col>
<col>
<tbody>
<tr>
<td valign="middle" width="30"></td>
<td align="justify">
Une <a href="http://knol.google.com/k/les-transactions-base-de-donn<6E>es"
target="_blank"><b>transaction</b></a> est une suite d'op<6F>rations effectu<74>es comme une seule unit<69>
logique de travail.<br>
Une fois termin<69>e, la transaction est :<br>
* soit valid<69>e (<b>commit</b>), alors toutes les modifications sont faites dans la base de donn<6E>es
;<br>
* soit annul<75>e (<b>rollback</b>), alors toutes les modifications ne sont pas enregistr<74>e.<br>
<br>
La classe <b><a href="../doxygen/html/classqx_1_1_qx_session.html"
target="_blank">qx::QxSession</a></b> de la biblioth<74>que QxOrm permet de g<>rer automatiquement les
transactions (validation, annulation) en utilisant le m<>canisme <a
href="http://fr.wikipedia.org/wiki/RAII" target="_blank">C++ RAII</a> :<br>
<br>
<table border="1" bgcolor="#FFFFFF">
<col>
<tbody>
<tr>
<td>
<pre><span class="operator">{</span><span class="comment"> // Ouverture d'un scope o<> une session sera instanci<63>e
// Cr<43>ation d'une session : une connection valide <20> la BDD est assign<67>e <20> la session et une transaction est d<>marr<72>e
</span>qx<span class="operator">::</span>QxSession session<span class="operator">;</span><span class="comment">
// Ex<45>cution d'une s<>rie d'op<6F>rations avec la BDD (en utilisant l'op<6F>rateur += de la classe qx::QxSession et la connection de la session)
</span>session<span class="operator"> +=</span> qx<span class="operator">::</span>dao<span class="operator">::</span>insert<span class="operator">(</span>my_object<span class="operator">,</span> session<span class="operator">.</span>database<span class="operator">());</span>
session<span class="operator"> +=</span> qx<span class="operator">::</span>dao<span class="operator">::</span>update<span class="operator">(</span>my_object<span class="operator">,</span> session<span class="operator">.</span>database<span class="operator">());</span>
session<span class="operator"> +=</span> qx<span class="operator">::</span>dao<span class="operator">::</span>fetch_by_id<span class="operator">(</span>my_object<span class="operator">,</span> session<span class="operator">.</span>database<span class="operator">());</span>
session<span class="operator"> +=</span> qx<span class="operator">::</span>dao<span class="operator">::</span>delete_by_id<span class="operator">(</span>my_object<span class="operator">,</span> session<span class="operator">.</span>database<span class="operator">());</span><span class="comment">
// Si la session n'est pas valide (donc une erreur s'est produite) =&gt; affichage de la 1<>re erreur de la session
</span><span class="flow">if</span><span class="operator"> (!</span> session<span class="operator">.</span>isValid<span class="operator">()) {</span> qDebug<span class="operator">(</span><span class="string">"[QxOrm] session error : '%s'"</span><span class="operator">,</span> qPrintable<span class="operator">(</span>session<span class="operator">.</span>firstError<span class="operator">().</span>text<span class="operator">())); }
}</span><span class="comment"> // Fermeture du scope : la session est d<>truite (transaction =&gt; commit ou rollback automatique)</span></pre>
</td>
</tr>
</tbody>
</table>
<br>
<b>Remarque :</b> une session peut d<>clencher une exception de type <i>qx::dao::sql_error</i>
lorsqu'une erreur se produit (par d<>faut, aucune exception n'est d<>clench<63>e). Il est possible de
param<61>trer ce comportement en utilisant :<br>
* soit le constructeur de la classe <i>qx::QxSession</i> (pour une session en particulier) ;<br>
* soit le param<61>tre du singleton <i>qx::QxSqlDatabase::getSingleton()->setSessionThrowable(bool b)</i>
(pour toutes les sessions).<br>
<br>
<b>Autre remarque :</b> il est important de ne pas oublier de passer la connection <20> la base de
donn<6E>es de la session <20> chaque fonction <i>qx::dao::xxx</i> (en utilisant la m<>thode
<i>session.database()</i>).<br>
De plus, il est possible d'initialiser une session avec sa propre connection (provenant d'un pool de
connections par exemple) en utilisant le constructeur de la classe <i>qx::QxSession</i>.<br>
<br>
La classe <i>qx::QxSession</i> propose <20>galement des m<>thodes de persistance (CRUD), ce qui peut
simplifier l'<27>criture du code C++ suivant les habitudes de programmation.<br>
Voici le m<>me exemple en utilisant les m<>thodes de la classe <i>qx::QxSession</i> <20> la place des
fonctions du <i>namespace</i> <i>qx::dao</i> :<br>
<br>
<table border="1" bgcolor="#FFFFFF">
<col>
<tbody>
<tr>
<td>
<pre><span class="operator">{</span><span class="comment"> // Ouverture d'un scope o<> une session sera instanci<63>e
// Cr<43>ation d'une session : une connection valide <20> la BDD est assign<67>e <20> la session et une transaction est d<>marr<72>e
</span> qx<span class="operator">::</span>QxSession session<span class="operator">;</span><span class="comment">
// Ex<45>cution d'une s<>rie d'op<6F>rations avec la BDD
</span> session<span class="operator">.</span>insert<span class="operator">(</span>my_object<span class="operator">);</span>
session<span class="operator">.</span>update<span class="operator">(</span>my_object<span class="operator">);</span>
session<span class="operator">.</span>fetchById<span class="operator">(</span>my_object<span class="operator">);</span>
session<span class="operator">.</span>deleteById<span class="operator">(</span>my_object<span class="operator">);</span><span class="comment">
// Si la session n'est pas valide (donc une erreur s'est produite) =&gt; affichage de la 1<>re erreur de la session
</span><span class="flow"> if</span><span class="operator"> (!</span> session<span class="operator">.</span>isValid<span class="operator">()) {</span> qDebug<span class="operator">(</span><span class="string">"[QxOrm] session error : '%s'"</span><span class="operator">,</span> qPrintable<span class="operator">(</span>session<span class="operator">.</span>firstError<span class="operator">().</span>text<span class="operator">())); }
}</span><span class="comment"> // Fermeture du scope : la session est d<>truite (transaction =&gt; commit ou rollback automatique)</span></pre>
</td>
</tr>
</tbody>
</table>
<br>
</td>
</tr>
</tbody>
</table>
<br><br>
<a name="faq_180"><u><b>Comment persister un type dont on ne poss<73>de pas le code source (classe provenant
d'une biblioth<74>que tierce par exemple) ?</b></u></a><br><br>
<table border="0" style="width: 100%" align="center">
<col>
<col>
<tbody>
<tr>
<td valign="middle" width="30"></td>
<td align="justify">
La biblioth<74>que QxOrm permet de persister n'importe quel type, m<>me si ce dernier n'est pas enregistr<74>
dans le contexte QxOrm par la m<>thode <i>qx::register_class&lt;T&gt;()</i>.<br>
<br>
Il est n<>cessaire d'<27>crire les fonctions de s<>rialisation de la biblioth<74>que boost, en utilisant la
m<>thode <b>non intrusive</b> (puisque le code source n'est pas disponible ou ne peut pas <20>tre
modifi<66>).
Pour plus d'informations sur la s<>rialisation des donn<6E>es avec la biblioth<74>que boost, rendez-vous sur
<a href="http://khayyam.developpez.com/articles/cpp/boost/serialization/" target="_blank">le tutoriel
de developpez.com</a>.<br>
<br>
Par exemple, imaginons une classe '<i>ExtObject3D</i>' provenant d'une biblioth<74>que tierce et dont le
code source n'est pas disponible ou ne peut pas <20>tre modifi<66>.
Voici le code n<>cessaire pour pouvoir persister une instance de type '<i>ExtObject3D</i>' en base de
donn<6E>es :<br>
<br>
<table border="1" bgcolor="#FFFFFF">
<col>
<tbody>
<tr>
<td>
<pre><span class="pre">#ifndef _PERSIST_EXTOBJECT3D_H_
#define _PERSIST_EXTOBJECT3D_H_
#include "ExtObject3D.h"
#include &lt;boost/serialization/serialization.hpp&gt;
#include &lt;boost/serialization/split_free.hpp&gt;
#include &lt;boost/serialization/nvp.hpp&gt;
</span><span class="keyword">
namespace</span> boost<span class="operator"> {</span><span class="keyword">
namespace</span> serialization<span class="operator"> {</span><span class="keyword">
template</span><span class="operator"> &lt;</span><span class="keyword">class</span> Archive<span class="operator">&gt;</span><span class="type">
void</span> save<span class="operator">(</span>Archive<span class="operator"> &amp;</span> ar<span class="operator">,</span><span class="keyword"> const</span> ExtObject3D<span class="operator"> &amp;</span> t<span class="operator">,</span><span class="type"> unsigned int</span> version<span class="operator">)
{</span>
Q_UNUSED<span class="operator">(</span>version<span class="operator">);</span><span class="type">
double</span> x<span class="operator">(</span>t<span class="operator">.</span>getX<span class="operator">()),</span> y<span class="operator">(</span>t<span class="operator">.</span>getY<span class="operator">()),</span> z<span class="operator">(</span>t<span class="operator">.</span>getZ<span class="operator">()),</span> angle<span class="operator">(</span>t<span class="operator">.</span>getAngle<span class="operator">());</span>
ar<span class="operator"> &lt;&lt;</span> boost<span class="operator">::</span>serialization<span class="operator">::</span>make_nvp<span class="operator">(</span><span class="string">"x"</span><span class="operator">,</span> x<span class="operator">);</span>
ar<span class="operator"> &lt;&lt;</span> boost<span class="operator">::</span>serialization<span class="operator">::</span>make_nvp<span class="operator">(</span><span class="string">"y"</span><span class="operator">,</span> y<span class="operator">);</span>
ar<span class="operator"> &lt;&lt;</span> boost<span class="operator">::</span>serialization<span class="operator">::</span>make_nvp<span class="operator">(</span><span class="string">"z"</span><span class="operator">,</span> z<span class="operator">);</span>
ar<span class="operator"> &lt;&lt;</span> boost<span class="operator">::</span>serialization<span class="operator">::</span>make_nvp<span class="operator">(</span><span class="string">"angle"</span><span class="operator">,</span> angle<span class="operator">);
}</span><span class="keyword">
template</span><span class="operator"> &lt;</span><span class="keyword">class</span> Archive<span class="operator">&gt;</span><span class="type">
void</span> load<span class="operator">(</span>Archive<span class="operator"> &amp;</span> ar<span class="operator">,</span> ExtObject3D<span class="operator"> &amp;</span> t<span class="operator">,</span><span class="type"> unsigned int</span> version<span class="operator">)
{</span>
Q_UNUSED<span class="operator">(</span>version<span class="operator">);</span><span class="type">
double</span> x<span class="operator">(</span><span class="float">0.0</span><span class="operator">),</span> y<span class="operator">(</span><span class="float">0.0</span><span class="operator">),</span> z<span class="operator">(</span><span class="float">0.0</span><span class="operator">),</span> angle<span class="operator">(</span><span class="float">0.0</span><span class="operator">);</span>
ar<span class="operator"> &gt;&gt;</span> boost<span class="operator">::</span>serialization<span class="operator">::</span>make_nvp<span class="operator">(</span><span class="string">"x"</span><span class="operator">,</span> x<span class="operator">);</span>
ar<span class="operator"> &gt;&gt;</span> boost<span class="operator">::</span>serialization<span class="operator">::</span>make_nvp<span class="operator">(</span><span class="string">"y"</span><span class="operator">,</span> y<span class="operator">);</span>
ar<span class="operator"> &gt;&gt;</span> boost<span class="operator">::</span>serialization<span class="operator">::</span>make_nvp<span class="operator">(</span><span class="string">"z"</span><span class="operator">,</span> z<span class="operator">);</span>
ar<span class="operator"> &gt;&gt;</span> boost<span class="operator">::</span>serialization<span class="operator">::</span>make_nvp<span class="operator">(</span><span class="string">"angle"</span><span class="operator">,</span> angle<span class="operator">);</span>
t<span class="operator">.</span>setX<span class="operator">(</span>x<span class="operator">);</span>
t<span class="operator">.</span>setY<span class="operator">(</span>y<span class="operator">);</span>
t<span class="operator">.</span>setZ<span class="operator">(</span>z<span class="operator">);</span>
t<span class="operator">.</span>setAngle<span class="operator">(</span>angle<span class="operator">);
}
}</span><span class="comment"> // namespace serialization
</span><span class="operator">}</span><span class="comment"> // namespace boost
</span>
BOOST_SERIALIZATION_SPLIT_FREE<span class="operator">(</span>ExtObject3D<span class="operator">)</span><span class="pre">
#endif // _PERSIST_EXTOBJECT3D_H_</span></pre>
</td>
</tr>
</tbody>
</table>
<br>
Le code ci-dessus est suffisant pour persister une instance de type '<i>ExtObject3D</i>' en base de
donn<6E>es : il est ainsi possible d'utiliser une propri<72>t<EFBFBD> de type '<i>ExtObject3D</i>' dans une classe
persistante enregistr<74>e dans le contexte QxOrm.
Cette propri<72>t<EFBFBD> peut <20>tre mapp<70>e sur une colonne de type <i>TEXT</i> ou <i>VARCHAR</i> en base de
donn<6E>es.<br>
<br>
Le comportement par d<>faut de la biblioth<74>que QxOrm est le suivant : l'instance est s<>rialis<69>e au
format XML avant d'<27>tre ins<6E>r<EFBFBD>e ou mise <20> jour en base de donn<6E>es.
Ce comportement par d<>faut peut <20>tre utile par exemple si l'on souhaite enregistrer une collection
d'objets sans vouloir faire de relation (et donc g<>rer une autre table dans la base de donn<6E>es).
Par exemple, si l'on utilise une propri<72>t<EFBFBD> de type <i>std::vector&lt;mon_objet&gt;</i> dans une classe
persistante sans relation associ<63>e, la liste d'<27>l<EFBFBD>ments sera automatiquement enregistr<74>e au format XML
en base de donn<6E>es.<br>
<br>
<b>Remarque :</b> ce comportement par d<>faut peut <20>tre facilement modifi<66> pour un type donn<6E>.
Le moteur <i>QtSql</i> utilise le type <i>QVariant</i> pour faire le lien entre le code C++ et la base
de donn<6E>es.
Le type <i>QVariant</i> peut contenir du texte, des valeurs num<75>riques, du binaire, etc.
Il peut donc <20>tre int<6E>ressant de sp<73>cialiser le comportement par d<>faut (s<>rialisation XML) si l'on
souhaite stocker des donn<6E>es au format binaire ou bien optimiser les performances (la s<>rialisation
XML peut <20>tre couteuse en temps d'ex<65>cution).
Il suffit de proposer (en plus des fonctions de s<>rialisation boost) les conversions n<>cessaires en
<i>QVariant</i>, par exemple avec la classe '<i>ExtObject3D</i>' :<br>
<br>
<table border="1" bgcolor="#FFFFFF">
<col>
<tbody>
<tr>
<td>
<pre><span class="keyword">namespace</span> qx<span class="operator"> {</span><span class="keyword">
namespace</span> cvt<span class="operator"> {</span><span class="keyword">
namespace</span> detail<span class="operator"> {</span><span class="keyword">
template</span><span class="operator"> &lt;&gt;</span><span class="keyword"> struct</span> QxConvert_ToVariant<span class="operator">&lt;</span> ExtObject3D<span class="operator"> &gt; {</span><span class="keyword">
static inline</span> QVariant toVariant<span class="operator">(</span><span class="keyword">const</span> ExtObject3D<span class="operator"> &amp;</span> t<span class="operator">,</span><span class="keyword"> const</span> QString<span class="operator"> &amp;</span> format<span class="operator">,</span><span class="type"> int</span> index<span class="operator">)
{</span><span class="comment"> /* Ici je convertis ExtObject3D en QVariant */</span><span class="operator"> } };</span><span class="keyword">
template</span><span class="operator"> &lt;&gt;</span><span class="keyword"> struct</span> QxConvert_FromVariant<span class="operator">&lt;</span> ExtObject3D<span class="operator"> &gt; {</span><span class="keyword">
static inline</span> qx_bool fromVariant<span class="operator">(</span><span class="keyword">const</span> QVariant<span class="operator"> &amp;</span> v<span class="operator">,</span> ExtObject3D<span class="operator"> &amp;</span> t<span class="operator">,</span><span class="keyword"> const</span> QString<span class="operator"> &amp;</span> format<span class="operator">,</span><span class="type"> int</span> index<span class="operator">)
{</span><span class="comment"> /* Ici je convertis QVariant en ExtObject3D */</span><span class="operator">;</span><span class="flow"> return</span> qx_bool<span class="operator">(</span><span class="bool">true</span><span class="operator">); } };
}</span><span class="comment"> // namespace detail
</span><span class="operator">}</span><span class="comment"> // namespace cvt
</span><span class="operator">}</span><span class="comment"> // namespace qx</span></pre>
</td>
</tr>
</tbody>
</table>
<br>
</td>
</tr>
</tbody>
</table>
<br><br>
<a name="faq_190"><u><b>Comment utiliser le moteur d'introspection (ou r<>flexion) de la biblioth<74>que QxOrm
?</b></u></a><br><br>
<table border="0" style="width: 100%" align="center">
<col>
<col>
<tbody>
<tr>
<td valign="middle" width="30"></td>
<td align="justify">
Toute classe enregistr<74>e dans le contexte QxOrm par la m<>thode <i>qx::register_class&lt;T&gt;()</i>
peut <20>tre utilis<69>e par le moteur d'introspection (ou r<>flexion) de la biblioth<74>que QxOrm.
Le moteur d'introspection permet d'obtenir de fa<66>on dynamique (donc pendant l'ex<65>cution du programme)
des informations propres <20> un type.
Ces informations correspondent <20> des <i>m<EFBFBD>ta-donn<6E>es</i> et d<>crivent de fa<66>on exhaustive les
caract<63>ristiques d'une classe (propri<72>t<EFBFBD>s, m<>thodes, etc.).
De nombreux langages de programmation (par exemple Java ou C#) int<6E>grent nativement ce m<>canisme, ce
n'est pas le cas du C++, c'est pourquoi la biblioth<74>que QxOrm <20>mule un moteur d'introspection.<br>
<br>
Voici la liste des classes disponibles pour acc<63>der aux <i>m<EFBFBD>ta-donn<6E>es</i> :
<ul>
<li><a href="../doxygen/html/classqx_1_1_qx_class_x.html" target="_blank">qx::QxClassX</a> :
singleton permettant de parcourir l'ensemble des classes enregistr<74>es dans le contexte QxOrm par
la m<>thode <i>qx::register_class&lt;T&gt;()</i> ;</li>
<li><a href="../doxygen/html/classqx_1_1_ix_class.html" target="_blank">qx::IxClass</a> : interface
pour une classe enregistr<74>e dans le contexte QxOrm ;</li>
<li><a href="../doxygen/html/classqx_1_1_ix_data_member_x.html"
target="_blank">qx::IxDataMemberX</a> : liste des propri<72>t<EFBFBD>s associ<63>es <20> une classe ;</li>
<li><a href="../doxygen/html/classqx_1_1_ix_data_member.html" target="_blank">qx::IxDataMember</a> :
interface pour une propri<72>t<EFBFBD> d'une classe ;</li>
<li><a href="../doxygen/html/classqx_1_1_ix_function.html" target="_blank">qx::IxFunctionX</a> :
liste des m<>thodes associ<63>es <20> une classe ;</li>
<li><a href="../doxygen/html/classqx_1_1_ix_function.html" target="_blank">qx::IxFunction</a> :
interface pour une m<>thode d'une classe.</li>
</ul>
Une instance de type <i>qx::IxClass</i> poss<73>de la liste des propri<72>t<EFBFBD>s d'une classe
(<i>qx::IxDataMemberX</i>) ainsi que la liste des m<>thodes d'une classe (<i>qx::IxFunctionX</i>).<br>
<br>
Le moteur d'introspection de la biblioth<74>que QxOrm permet par exemple de :
<ul>
<li>cr<EFBFBD>er dynamiquement une instance en fonction du nom d'une classe sous forme de cha<68>ne de
caract<63>res (<i>qx::create()</i>) ;</li>
<li>acc<EFBFBD>der/modifier le contenu d'un champ d'un objet de fa<66>on dynamique en prenant pour param<61>tres
un objet et le nom du champ qu'on souhaite acc<63>der/modifier (<i>qx::IxDataMember::getValue()</i>
et <i>qx::IxDataMember::setValue()</i>) ;</li>
<li>invoquer une m<>thode de classe de fa<66>on dynamique, en g<>rant bien entendu le passage des
param<61>tres souhait<69>s <20> la m<>thode (<i>qx::IxFunction::invoke()</i>) ;</li>
<li>acc<EFBFBD>der <20> la hi<68>rarchie d'une classe (<i>qx::IxClass::getBaseClass()</i>).</li>
</ul>
<b>Remarque :</b> le module <a href="../doxygen/html/group___qx_service.html"
target="_blank">QxService</a> de la biblioth<74>que QxOrm (<a href="./tutorial_2.html"
target="_blank">cliquez ici pour acc<63>der au tutoriel</a>) permettant de cr<63>er un serveur
d'applications C++ est bas<61> sur le moteur d'introspection pour appeler dynamiquement les m<>thodes de
type service (demande du client) sur le serveur.<br>
<br>
Voici un exemple d'utilisation du moteur d'introspection de la biblioth<74>que QxOrm : comment lister
toutes les classes, propri<72>t<EFBFBD>s et m<>thodes enregistr<74>es dans le contexte QxOrm ?<br>
<br>
<table border="1" bgcolor="#FFFFFF">
<col>
<tbody>
<tr>
<td>
<pre>QString QxClassX<span class="operator">::</span>dumpAllClasses<span class="operator">()
{</span>
QxClassX<span class="operator">::</span>registerAllClasses<span class="operator">();</span>
QxCollection<span class="operator">&lt;</span>QString<span class="operator">,</span> IxClass<span class="operator"> *&gt; *</span> pAllClasses<span class="operator"> =</span> QxClassX<span class="operator">::</span>getAllClasses<span class="operator">();</span><span class="flow">
if</span><span class="operator"> (!</span> pAllClasses<span class="operator">) {</span> qAssert<span class="operator">(</span><span class="bool">false</span><span class="operator">);</span><span class="flow"> return</span><span class="string"> ""</span><span class="operator">; }</span>
QString sDump<span class="operator">;</span><span class="type">
long</span> lCount<span class="operator"> =</span> pAllClasses<span class="operator">-&gt;</span>count<span class="operator">();</span>
qDebug<span class="operator">(</span><span class="string">"[QxOrm] start dump all registered classes (%ld)"</span><span class="operator">,</span> lCount<span class="operator">);</span>
_foreach<span class="operator">(</span>IxClass<span class="operator"> *</span> pClass<span class="operator">, (*</span> pAllClasses<span class="operator">))
{</span><span class="flow"> if</span><span class="operator"> (</span>pClass<span class="operator">) {</span> sDump<span class="operator"> +=</span> pClass<span class="operator">-&gt;</span>dumpClass<span class="operator">(); } }</span>
qDebug<span class="operator">(</span><span class="string">"[QxOrm] %s"</span><span class="operator">,</span><span class="string"> "end dump all registered classes"</span><span class="operator">);</span><span class="flow">
return</span> sDump<span class="operator">;
}</span>
QString IxClass<span class="operator">::</span>dumpClass<span class="operator">()</span><span class="keyword"> const</span><span class="operator">
{</span>
QString sDump<span class="operator">;</span>
sDump<span class="operator"> +=</span><span class="string"> "-- class '"</span><span class="operator"> +</span> m_sKey<span class="operator"> +</span><span class="string"> "' (name '"</span><span class="operator"> +</span> m_sName<span class="operator"> +</span><span class="string"> "', "</span><span class="operator">;</span>
sDump<span class="operator"> +=</span><span class="string"> "description '"</span><span class="operator"> +</span> m_sDescription<span class="operator"> +</span><span class="string"> "', version '"</span><span class="operator"> +</span> QString<span class="operator">::</span>number<span class="operator">(</span>m_lVersion<span class="operator">) +</span><span class="string"> "', "</span><span class="operator">;</span>
sDump<span class="operator"> +=</span><span class="string"> "base class '"</span><span class="operator"> + (</span>getBaseClass<span class="operator">() ?</span> getBaseClass<span class="operator">()-&gt;</span>getKey<span class="operator">() :</span><span class="string"> ""</span><span class="operator">) +</span><span class="string"> "')\n"</span><span class="operator">;</span><span class="type">
long</span> lCount<span class="operator"> = (</span>m_pDataMemberX<span class="operator"> ?</span> m_pDataMemberX<span class="operator">-&gt;</span>count<span class="operator">() :</span><span class="int"> 0</span><span class="operator">);</span>
sDump<span class="operator"> +=</span><span class="string"> "\t* list of registered properties ("</span><span class="operator"> +</span> QString<span class="operator">::</span>number<span class="operator">(</span>lCount<span class="operator">) +</span><span class="string"> ")\n"</span><span class="operator">;</span><span class="flow">
if</span><span class="operator"> (</span>m_pDataMemberX<span class="operator">)
{</span>
IxDataMember<span class="operator"> *</span> pId<span class="operator"> =</span><span class="keyword"> this</span><span class="operator">-&gt;</span>getId<span class="operator">();</span><span class="flow">
for</span><span class="operator"> (</span><span class="type">long</span> l<span class="operator"> =</span><span class="int"> 0</span><span class="operator">;</span> l<span class="operator"> &lt;</span> lCount<span class="operator">;</span> l<span class="operator">++)
{</span>
IxDataMember<span class="operator"> *</span> p<span class="operator"> =</span> m_pDataMemberX<span class="operator">-&gt;</span>get<span class="operator">(</span>l<span class="operator">);</span><span class="flow"> if</span><span class="operator"> (!</span> p<span class="operator">) {</span><span class="flow"> continue</span><span class="operator">; }</span>
IxSqlRelation<span class="operator"> *</span> pRelation<span class="operator"> =</span> p<span class="operator">-&gt;</span>getSqlRelation<span class="operator">();</span>
QString sInfos<span class="operator"> =</span> p<span class="operator">-&gt;</span>getKey<span class="operator">() + ((</span>p<span class="operator"> ==</span> pId<span class="operator">) ?</span> QString<span class="operator">(</span><span class="string">" (id)"</span><span class="operator">) :</span> QString<span class="operator">());</span>
sInfos<span class="operator"> += (</span>pRelation<span class="operator"> ? (</span>QString<span class="operator">(</span><span class="string">" ("</span><span class="operator">) +</span> pRelation<span class="operator">-&gt;</span>getDescription<span class="operator">() +</span> QString<span class="operator">(</span><span class="string">")"</span><span class="operator">)) :</span> QString<span class="operator">());</span>
sDump<span class="operator"> +=</span><span class="string"> "\t\t"</span><span class="operator"> +</span> sInfos<span class="operator"> +</span><span class="string"> "\n"</span><span class="operator">;
}
}</span>
lCount<span class="operator"> = (</span>m_pFctMemberX<span class="operator"> ?</span> m_pFctMemberX<span class="operator">-&gt;</span>count<span class="operator">() :</span><span class="int"> 0</span><span class="operator">);</span>
sDump<span class="operator"> +=</span><span class="string"> "\t* list of registered functions ("</span><span class="operator"> +</span> QString<span class="operator">::</span>number<span class="operator">(</span>lCount<span class="operator">) +</span><span class="string"> ")\n"</span><span class="operator">;</span><span class="flow">
if</span><span class="operator"> (</span>m_pFctMemberX<span class="operator">)
{</span>
_foreach_if<span class="operator">(</span>IxFunction_ptr p<span class="operator">, (*</span> m_pFctMemberX<span class="operator">), (</span>p<span class="operator">))
{</span> QString sKey<span class="operator"> =</span> p<span class="operator">-&gt;</span>getKey<span class="operator">();</span> sDump<span class="operator"> +=</span><span class="string"> "\t\t"</span><span class="operator"> +</span> sKey<span class="operator"> +</span><span class="string"> "\n"</span><span class="operator">; }
}</span>
qDebug<span class="operator">(</span><span class="string">"%s"</span><span class="operator">,</span> qPrintable<span class="operator">(</span>sDump<span class="operator">));</span><span class="flow">
return</span> sDump<span class="operator">;
}</span></pre>
</td>
</tr>
</tbody>
</table>
<br>
Si on utilise la m<>thode <i>qx::QxClassX::dumpAllClasses()</i> avec le <a href="./tutorial.html"
target="_blank">tutoriel qxBlog</a>, voici le r<>sultat obtenu :<br>
<br>
<table border="1" bgcolor="#FFFFFF">
<col>
<tbody>
<tr>
<td>
<pre><span class="operator">[</span>QxOrm<span class="operator">]</span> start dump all registered classes<span class="operator"> (</span><span class="int">4</span><span class="operator">)
--</span><span class="keyword"> class</span><span class="char"> 'author'</span><span class="operator"> (</span>name<span class="char"> 'author'</span><span class="operator">,</span> description<span class="char"> ''</span><span class="operator">,</span> version<span class="char"> '0'</span><span class="operator">,</span> base<span class="keyword"> class</span><span class="char"> ''</span><span class="operator">)
*</span> list of registered properties<span class="operator"> (</span><span class="int">5</span><span class="operator">)</span>
author_id<span class="operator"> (</span>id<span class="operator">)</span>
name
birthdate
sex
list_blog<span class="operator"> (</span>relation one<span class="operator">-</span>to<span class="operator">-</span>many<span class="operator">)
*</span> list of registered functions<span class="operator"> (</span><span class="int">1</span><span class="operator">)</span>
age<span class="operator">
--</span><span class="keyword"> class</span><span class="char"> 'blog'</span><span class="operator"> (</span>name<span class="char"> 'blog'</span><span class="operator">,</span> description<span class="char"> ''</span><span class="operator">,</span> version<span class="char"> '0'</span><span class="operator">,</span> base<span class="keyword"> class</span><span class="char"> ''</span><span class="operator">)
*</span> list of registered properties<span class="operator"> (</span><span class="int">6</span><span class="operator">)</span>
blog_id<span class="operator"> (</span>id<span class="operator">)</span>
blog_text
date_creation
author_id<span class="operator"> (</span>relation many<span class="operator">-</span>to<span class="operator">-</span>one<span class="operator">)</span>
list_comment<span class="operator"> (</span>relation one<span class="operator">-</span>to<span class="operator">-</span>many<span class="operator">)</span>
list_category<span class="operator"> (</span>relation many<span class="operator">-</span>to<span class="operator">-</span>many<span class="operator">)
*</span> list of registered functions<span class="operator"> (</span><span class="int">0</span><span class="operator">)
--</span><span class="keyword"> class</span><span class="char"> 'comment'</span><span class="operator"> (</span>name<span class="char"> 'comment'</span><span class="operator">,</span> description<span class="char"> ''</span><span class="operator">,</span> version<span class="char"> '0'</span><span class="operator">,</span> base<span class="keyword"> class</span><span class="char"> ''</span><span class="operator">)
*</span> list of registered properties<span class="operator"> (</span><span class="int">4</span><span class="operator">)</span>
comment_id<span class="operator"> (</span>id<span class="operator">)</span>
comment_text
date_creation
blog_id<span class="operator"> (</span>relation many<span class="operator">-</span>to<span class="operator">-</span>one<span class="operator">)
*</span> list of registered functions<span class="operator"> (</span><span class="int">0</span><span class="operator">)
--</span><span class="keyword"> class</span><span class="char"> 'category'</span><span class="operator"> (</span>name<span class="char"> 'category'</span><span class="operator">,</span> description<span class="char"> ''</span><span class="operator">,</span> version<span class="char"> '0'</span><span class="operator">,</span> base<span class="keyword"> class</span><span class="char"> ''</span><span class="operator">)
*</span> list of registered properties<span class="operator"> (</span><span class="int">4</span><span class="operator">)</span>
category_id<span class="operator"> (</span>id<span class="operator">)</span>
name
description
list_blog<span class="operator"> (</span>relation many<span class="operator">-</span>to<span class="operator">-</span>many<span class="operator">)
*</span> list of registered functions<span class="operator"> (</span><span class="int">0</span><span class="operator">)
[</span>QxOrm<span class="operator">]</span> end dump all registered classes</pre>
</td>
</tr>
</tbody>
</table>
<br>
<b>Remarque :</b> il est possible d'ajouter de nouvelles informations au moteur d'introspection en
utilisant la notion de <i>property bag</i>.
En effet, les classes <i>qx::IxClass</i>, <i>qx::IxDataMember</i> et <i>qx::IxFunction</i> poss<73>dent
chacune une liste d'<27>l<EFBFBD>ments de type <i>QVariant</i> accessibles par cl<63> de type <i>QString</i> (voir
la classe <i>qx::QxPropertyBag</i> pour plus de d<>tails sur cette notion).<br>
<br>
</td>
</tr>
</tbody>
</table>
<br><br>
<a name="faq_200"><u><b>Comment d<>clarer automatiquement les m<>ta-propri<72>t<EFBFBD>s de Qt (d<>finies par la macro
<i>Q_PROPERTY</i>) dans le contexte QxOrm ?</b></u></a><br><br>
<table border="0" style="width: 100%" align="center">
<col>
<col>
<tbody>
<tr>
<td valign="middle" width="30"></td>
<td align="justify">
Toute classe h<>ritant du type <i>QObject</i> peut d<>clarer ses propri<72>t<EFBFBD>s avec la macro <i><a
href="http://doc-snapshots.qt.io/4.8/properties.html" target="_blank">Q_PROPERTY</a></i> : les
propri<72>t<EFBFBD>s deviennent alors des m<>ta-propri<72>t<EFBFBD>s.
Ce m<>canisme permet au framework Qt de proposer un moteur d'introspection gr<67>ce au pr<70>-compilateur
<i>moc</i>.
Les m<>ta-propri<72>t<EFBFBD>s peuvent alors <20>tre utilis<69>es par exemple par le moteur <i>QML</i>,
<i>QtScript</i>, etc.<br>
<br>
La biblioth<74>que <b>QxOrm</b> n<>cessite une d<>claration de chacune des propri<72>t<EFBFBD>s d'une classe dans la
fonction de mapping <i>void qx::register_class&lt;T&gt;()</i> afin de proposer l'ensemble de ses
fonctionnalit<69>s (persistance des donn<6E>es, s<>rialisation XML, JSON et binaire, etc.).
Il est possible de d<>clarer automatiquement dans le contexte QxOrm l'ensemble des m<>ta-propri<72>t<EFBFBD>s sans
maintenir une fonction de mapping <i>void qx::register_class&lt;T&gt;()</i> : la macro
<b>QX_REGISTER_ALL_QT_PROPERTIES()</b> utilise le moteur d'introspection de Qt pour parcourir la liste
des m<>ta-propri<72>t<EFBFBD>s.<br>
<br>
Voici un exemple d'utilisation avec la classe <i>TestQtProperty</i> se trouvant dans le dossier
<i>./test/qxDllSample/dll1/include/</i> de la distribution QxOrm :<br>
<br>
<table border="1" bgcolor="#FFFFFF">
<col>
<tbody>
<tr>
<td title="TestQtProperty.h">
<pre><span class="pre">#ifndef _QX_TEST_QT_META_PROPERTY_H_
#define _QX_TEST_QT_META_PROPERTY_H_
</span><span class="keyword">
class</span> QX_DLL1_EXPORT TestQtProperty<span class="operator"> :</span><span class="keyword"> public</span> QObject<span class="operator">
{</span>
Q_OBJECT
Q_PROPERTY<span class="operator">(</span><span class="type">int</span> id READ id WRITE setId<span class="operator">)</span>
Q_PROPERTY<span class="operator">(</span><span class="type">long</span> number READ number WRITE setNumber<span class="operator">)</span>
Q_PROPERTY<span class="operator">(</span>QString desc READ desc WRITE setDesc<span class="operator">)</span>
Q_PROPERTY<span class="operator">(</span>QDateTime birthDate READ birthDate WRITE setBirthDate<span class="operator">)</span>
Q_PROPERTY<span class="operator">(</span>QVariant photo READ photo WRITE setPhoto<span class="operator">)</span><span class="keyword">
protected</span><span class="operator">:</span><span class="type">
int</span> m_id<span class="operator">;</span><span class="type">
long</span> m_number<span class="operator">;</span>
QString m_desc<span class="operator">;</span>
QDateTime m_birthDate<span class="operator">;</span>
QVariant m_photo<span class="operator">;</span><span class="keyword">
public</span><span class="operator">:</span>
TestQtProperty<span class="operator">() :</span> QObject<span class="operator">(),</span> m_id<span class="operator">(</span><span class="int">0</span><span class="operator">),</span> m_number<span class="operator">(</span><span class="int">0</span><span class="operator">) { ; }</span><span class="keyword">
virtual</span><span class="operator"> ~</span>TestQtProperty<span class="operator">() { ; }</span><span class="type">
int</span> id<span class="operator">()</span><span class="keyword"> const</span><span class="operator"> {</span><span class="flow"> return</span> m_id<span class="operator">; }</span><span class="type">
long</span> number<span class="operator">()</span><span class="keyword"> const</span><span class="operator"> {</span><span class="flow"> return</span> m_number<span class="operator">; }</span>
QString desc<span class="operator">()</span><span class="keyword"> const</span><span class="operator"> {</span><span class="flow"> return</span> m_desc<span class="operator">; }</span>
QDateTime birthDate<span class="operator">()</span><span class="keyword"> const</span><span class="operator"> {</span><span class="flow"> return</span> m_birthDate<span class="operator">; }</span>
QVariant photo<span class="operator">()</span><span class="keyword"> const</span><span class="operator"> {</span><span class="flow"> return</span> m_photo<span class="operator">; }</span><span class="type">
void</span> setId<span class="operator">(</span><span class="type">int</span> i<span class="operator">) {</span> m_id<span class="operator"> =</span> i<span class="operator">; }</span><span class="type">
void</span> setNumber<span class="operator">(</span><span class="type">long</span> l<span class="operator">) {</span> m_number<span class="operator"> =</span> l<span class="operator">; }</span><span class="type">
void</span> setDesc<span class="operator">(</span><span class="keyword">const</span> QString<span class="operator"> &amp;</span> s<span class="operator">) {</span> m_desc<span class="operator"> =</span> s<span class="operator">; }</span><span class="type">
void</span> setBirthDate<span class="operator">(</span><span class="keyword">const</span> QDateTime<span class="operator"> &amp;</span> dt<span class="operator">) {</span> m_birthDate<span class="operator"> =</span> dt<span class="operator">; }</span><span class="type">
void</span> setPhoto<span class="operator">(</span><span class="keyword">const</span> QVariant<span class="operator"> &amp;</span> v<span class="operator">) {</span> m_photo<span class="operator"> =</span> v<span class="operator">; }
};</span>
QX_REGISTER_HPP_QX_DLL1<span class="operator">(</span>TestQtProperty<span class="operator">,</span> QObject<span class="operator">,</span><span class="int"> 0</span><span class="operator">)</span><span class="pre">
#endif // _QX_TEST_QT_META_PROPERTY_H_</span></pre>
</td>
</tr>
</tbody>
</table>
<br>
<table border="1" bgcolor="#FFFFFF">
<col>
<tbody>
<tr>
<td title="TestQtProperty.cpp">
<pre><span class="pre">#include "../include/precompiled.h"
#include "../include/TestQtProperty.h"
#include &lt;QxOrm_Impl.h&gt;
</span>
QX_REGISTER_CPP_QX_DLL1<span class="operator">(</span>TestQtProperty<span class="operator">)</span>
QX_REGISTER_ALL_QT_PROPERTIES<span class="operator">(</span>TestQtProperty<span class="operator">,</span><span class="string"> "id"</span><span class="operator">)</span></pre>
</td>
</tr>
</tbody>
</table>
<br>
Pour ceux qui ne souhaitent pas utiliser la macro <i>QX_REGISTER_ALL_QT_PROPERTIES</i>, il est
possible d'<27>crire <20> la place les quatre lignes de code suivantes :<br>
<br>
<table border="1" bgcolor="#FFFFFF">
<col>
<tbody>
<tr>
<td>
<pre><span class="keyword">namespace</span> qx<span class="operator"> {</span><span class="keyword">
template</span><span class="operator"> &lt;&gt;</span><span class="type"> void</span> register_class<span class="operator">(</span>QxClass<span class="operator">&lt;</span>TestQtProperty<span class="operator">&gt; &amp;</span> t<span class="operator">)
{</span> qx<span class="operator">::</span>register_all_qt_properties<span class="operator">&lt;</span>TestQtProperty<span class="operator">&gt;(</span>t<span class="operator">,</span><span class="string"> "id"</span><span class="operator">); }
}</span><span class="comment"> // namespace qx</span></pre>
</td>
</tr>
</tbody>
</table>
<br>
<b>Remarque :</b> le deuxi<78>me param<61>tre de la macro <i>QX_REGISTER_ALL_QT_PROPERTIES</i> permet
d'indiquer la propri<72>t<EFBFBD> qui servira de cl<63> primaire dans la base de donn<6E>es.
Si ce param<61>tre est vide, cela signifie que la classe ne poss<73>de pas de cl<63> primaire ou bien que
celle-ci est d<>finie dans une classe de base.<br>
<br>
Toute propri<72>t<EFBFBD> d<>finie avec la macro <i>Q_PROPERTY</i> peut s'enregistrer dans le contexte QxOrm de
deux mani<6E>res diff<66>rentes :<br>
<b>1-</b> par la m<>thode classique : <i>t.data(& MyQObject::my_property, "my_property", 0);</i><br>
<b>2-</b> ou bien sans mentionner le pointeur vers la donn<6E>e membre de la classe :
<i>t.data("my_property", 0);</i><br>
<br>
Peu importe la m<>thode d'enregistrement des propri<72>t<EFBFBD>s dans le contexte QxOrm, elles seront
accessibles par la m<>me interface <i><a href="../doxygen/html/classqx_1_1_ix_data_member.html"
target="_blank">qx::IxDataMember</a></i> et proposent donc les m<>mes fonctionnalit<69>s.
Il est possible d'utiliser les deux m<>thodes dans une m<>me fonction de mapping <i>void
qx::register_class&lt;T&gt;()</i>.
Chaque m<>thode d'enregistrement pr<70>sente des avantages et inconv<6E>nients.<br>
<br>
Voici la liste des avantages de la deuxi<78>me m<>thode d'enregistrement des propri<72>t<EFBFBD>s dans le contexte
QxOrm :
<ul>
<li>temps de compilation du projet beaucoup plus rapide ;</li>
<li>taille de l'ex<65>cutable g<>n<EFBFBD>r<EFBFBD> plus petite ;</li>
<li>forte int<6E>gration avec le moteur d'introspection du framework Qt ;</li>
<li>pas besoin de maintenir la fonction de mapping en utilisant la macro
<i>QX_REGISTER_ALL_QT_PROPERTIES</i>.
</li>
</ul>
Voici les inconv<6E>nients par rapport <20> la m<>thode classique d'enregistrement des propri<72>t<EFBFBD>s :
<ul>
<li>n<EFBFBD>cessite un h<>ritage de la classe <i>QObject</i> pour pouvoir utiliser la macro
<i>Q_PROPERTY</i> ;
</li>
<li>ex<EFBFBD>cution du programme plus lente (utilisation du type <i>QVariant</i> <20> la place des
<i>template</i> C++) ;
</li>
<li>ne supporte pas la notion de relation entre tables de la base de donn<6E>es (<i>one-to-one</i>,
<i>one-to-many</i>, <i>many-to-one</i> et <i>many-to-many</i>) ;
</li>
<li>pas d'acc<63>s au pointeur sur la donn<6E>e membre de la classe (conversion n<>cessaire au type
<i>QVariant</i> pour acc<63>der et modifier une valeur).
</li>
</ul>
</td>
</tr>
</tbody>
</table>
<br><br>
<a name="faq_210"><u><b>Comment construire une requ<71>te pour interroger la base de donn<6E>es sans <20>crire de SQL
avec la classe <i>qx::QxSqlQuery</i> ?</b></u></a><br><br>
<table border="0" style="width: 100%" align="center">
<col>
<col>
<tbody>
<tr>
<td valign="middle" width="30"></td>
<td align="justify">
La classe <i><a href="../doxygen/html/classqx_1_1_qx_sql_query.html"
target="_blank">qx::QxSqlQuery</a></i> (ou bien son alias <i>qx_query</i>) permet d'interroger la
base de donn<6E>es (trier, filtrer, etc.) de deux mani<6E>res diff<66>rentes :
<ul>
<li>en <20>crivant directement la requ<71>te SQL ;</li>
<li>en utilisant des m<>thodes C++ avec une syntaxe proche du SQL (similaire <20> ce que propose <a
href="http://subsonicproject.com/docs/Simple_Query_Tool" target="_blank">l'excellente
biblioth<74>que SubSonic pour .Net</a>).</li>
</ul>
Le principal avantage de la premi<6D>re m<>thode (<28>criture manuelle des requ<71>tes SQL) est de pouvoir
utiliser certaines optimisations sp<73>cifiques <20> chaque base de donn<6E>es.<br>
La deuxi<78>me m<>thode (utilisation du code C++ pour g<>n<EFBFBD>rer la requ<71>te SQL) permet de mapper
automatiquement les param<61>tres SQL sans utiliser la fonction <i>qx::QxSqlQuery::bind()</i>.<br>
<br>
Voici un exemple d'utilisation de la classe <i>qx::QxSqlQuery</i> avec <20>criture manuelle d'une requ<71>te
SQL :<br>
<br>
<table border="1" bgcolor="#FFFFFF">
<col>
<tbody>
<tr>
<td>
<pre><span class="comment">// Construit une requ<71>te pour r<>cup<75>rer uniquement les 'author' de type 'female'
</span>qx<span class="operator">::</span>QxSqlQuery query<span class="operator">(</span><span class="string">"WHERE author.sex = :sex"</span><span class="operator">);</span>
query<span class="operator">.</span>bind<span class="operator">(</span><span class="string">":sex"</span><span class="operator">,</span> author<span class="operator">::</span>female<span class="operator">);</span>
QList<span class="operator">&lt;</span>author<span class="operator">&gt;</span> list_of_female<span class="operator">;</span>
QSqlError daoError<span class="operator"> =</span> qx<span class="operator">::</span>dao<span class="operator">::</span>fetch_by_query<span class="operator">(</span>query<span class="operator">,</span> list_of_female<span class="operator">);</span><span class="flow">
for</span><span class="operator"> (</span><span class="type">long</span> l<span class="operator"> =</span><span class="int"> 0</span><span class="operator">;</span> l<span class="operator"> &lt;</span> list_of_female<span class="operator">.</span>count<span class="operator">();</span> l<span class="operator">++)
{</span><span class="comment"> /* traitement avec la collection issue de la base de donn<6E>es */</span><span class="operator"> }</span></pre>
</td>
</tr>
</tbody>
</table>
<br>
La biblioth<74>que QxOrm supporte trois syntaxes pour l'<27>criture des param<61>tres SQL.<br>
Le type de syntaxe peut <20>tre modifi<66> de fa<66>on globale <20> un projet en utilisant la m<>thode suivante :
<i>qx::QxSqlDatabase::getSingleton()->setSqlPlaceHolderStyle()</i>.<br>
Les trois param<61>tres possibles pour cette m<>thode sont :
<ul>
<li><i>ph_style_2_point_name</i> : "WHERE author.sex = :sex" (syntaxe par d<>faut) ;</li>
<li><i>ph_style_at_name</i> : "WHERE author.sex = @sex" ;</li>
<li><i>ph_style_question_mark</i> : "WHERE author.sex = ?".</li>
</ul>
Voici le m<>me exemple en utilisant les m<>thodes C++ de la classe <i>qx::QxSqlQuery</i> (ou bien son
alias <i>qx_query</i>) pour g<>n<EFBFBD>rer la requ<71>te automatiquement :<br>
<br>
<table border="1" bgcolor="#FFFFFF">
<col>
<tbody>
<tr>
<td>
<pre><span class="comment">// Construit une requ<71>te pour r<>cup<75>rer uniquement les 'author' de type 'female'
</span>qx_query query<span class="operator">;</span>
query<span class="operator">.</span>where<span class="operator">(</span><span class="string">"author.sex"</span><span class="operator">).</span>isEqualTo<span class="operator">(</span>author<span class="operator">::</span>female<span class="operator">);</span>
QList<span class="operator">&lt;</span>author<span class="operator">&gt;</span> list_of_female<span class="operator">;</span>
QSqlError daoError<span class="operator"> =</span> qx<span class="operator">::</span>dao<span class="operator">::</span>fetch_by_query<span class="operator">(</span>query<span class="operator">,</span> list_of_female<span class="operator">);</span><span class="flow">
for</span><span class="operator"> (</span><span class="type">long</span> l<span class="operator"> =</span><span class="int"> 0</span><span class="operator">;</span> l<span class="operator"> &lt;</span> list_of_female<span class="operator">.</span>count<span class="operator">();</span> l<span class="operator">++)
{</span><span class="comment"> /* traitement avec la collection issue de la base de donn<6E>es */</span><span class="operator"> }</span></pre>
</td>
</tr>
</tbody>
</table>
<br>
Cette utilisation de la classe <i>qx::QxSqlQuery</i> pr<70>sente l'avantage de ne pas avoir <20> mapper les
param<61>tres de la requ<71>te, tout en restant tr<74>s proche de l'<27>criture manuelle d'une requ<71>te SQL.<br>
Les param<61>tres seront automatiquement inject<63>s en utilisant la syntaxe d<>finie de mani<6E>re globale par
la m<>thode : <i>qx::QxSqlDatabase::getSingleton()->getSqlPlaceHolderStyle()</i>.<br>
<br>
Voici un exemple pr<70>sentant diff<66>rentes m<>thodes disponibles avec la classe <i>qx::QxSqlQuery</i> (ou
bien son alias <i>qx_query</i>) :<br>
<br>
<table border="1" bgcolor="#FFFFFF">
<col>
<tbody>
<tr>
<td>
<pre>qx_query query<span class="operator">;</span>
query<span class="operator">.</span>where<span class="operator">(</span><span class="string">"sex"</span><span class="operator">).</span>isEqualTo<span class="operator">(</span>author<span class="operator">::</span>female<span class="operator">)
.</span>and_<span class="operator">(</span><span class="string">"age"</span><span class="operator">).</span>isGreaterThan<span class="operator">(</span><span class="int">38</span><span class="operator">)
.</span>or_<span class="operator">(</span><span class="string">"last_name"</span><span class="operator">).</span>isNotEqualTo<span class="operator">(</span><span class="string">"Dupont"</span><span class="operator">)
.</span>or_<span class="operator">(</span><span class="string">"first_name"</span><span class="operator">).</span>like<span class="operator">(</span><span class="string">"Alfred"</span><span class="operator">)
.</span>and_OpenParenthesis<span class="operator">(</span><span class="string">"id"</span><span class="operator">).</span>isLessThanOrEqualTo<span class="operator">(</span><span class="int">999</span><span class="operator">)
.</span>and_<span class="operator">(</span><span class="string">"birth_date"</span><span class="operator">).</span>isBetween<span class="operator">(</span>date1<span class="operator">,</span> date2<span class="operator">)
.</span>closeParenthesis<span class="operator">()
.</span>or_<span class="operator">(</span><span class="string">"id"</span><span class="operator">).</span>in<span class="operator">(</span><span class="int">50</span><span class="operator">,</span><span class="int"> 999</span><span class="operator">,</span><span class="int"> 11</span><span class="operator">,</span><span class="int"> 23</span><span class="operator">,</span><span class="int"> 78945</span><span class="operator">)
.</span>and_<span class="operator">(</span><span class="string">"is_deleted"</span><span class="operator">).</span>isNotNull<span class="operator">()
.</span>orderAsc<span class="operator">(</span><span class="string">"last_name"</span><span class="operator">,</span><span class="string"> "first_name"</span><span class="operator">,</span><span class="string"> "sex"</span><span class="operator">)
.</span>limit<span class="operator">(</span><span class="int">50</span><span class="operator">,</span><span class="int"> 150</span><span class="operator">);</span></pre>
</td>
</tr>
</tbody>
</table>
<br>
Ce qui produira le code SQL suivant pour les bases de donn<6E>es <i>MySQL</i>, <i>PostgreSQL</i> et
<i>SQLite</i> (pour <i>Oracle</i> et <i>SQLServer</i>, le traitement de la m<>thode <i>limit()</i> est
diff<66>rent) :<br>
<br>
<table border="1" bgcolor="#FFFFFF">
<col>
<tbody>
<tr>
<td>
<pre>WHERE sex<span class="operator"> = :</span>sex_1_0
AND age<span class="operator"> &gt; :</span>age_3_0
OR last_name<span class="operator"> &lt;&gt; :</span>last_name_5_0
OR first_name LIKE<span class="operator"> :</span>first_name_7_0
AND<span class="operator"> (</span> id<span class="operator"> &lt;= :</span>id_10_0 AND birth_date BETWEEN<span class="operator"> :</span>birth_date_12_0_1 AND<span class="operator"> :</span>birth_date_12_0_2<span class="operator"> )</span>
OR id IN<span class="operator"> (:</span>id_15_0_0<span class="operator">, :</span>id_15_0_1<span class="operator">, :</span>id_15_0_2<span class="operator">, :</span>id_15_0_3<span class="operator">, :</span>id_15_0_4<span class="operator">)</span>
AND is_deleted IS NOT NULL
ORDER BY last_name ASC<span class="operator">,</span> first_name ASC<span class="operator">,</span> sex ASC
LIMIT<span class="operator"> :</span>limit_rows_count_19_0 OFFSET<span class="operator"> :</span>offset_start_row_19_0</pre>
</td>
</tr>
</tbody>
</table>
<br>
Voici la liste des fonctions et m<>thodes disponibles pour utiliser la classe <i>qx::QxSqlQuery</i> (ou
bien son alias <i>qx_query</i>) :<br>
<br>
<table border="1" bgcolor="#FFFFFF">
<col>
<tbody>
<tr>
<td>
<pre><span class="comment">// avec les fonctions du namespace qx::dao
</span>qx<span class="operator">::</span>dao<span class="operator">::</span>count<span class="operator">&lt;</span>T<span class="operator">&gt;()</span>
qx<span class="operator">::</span>dao<span class="operator">::</span>fetch_by_query<span class="operator">&lt;</span>T<span class="operator">&gt;()</span>
qx<span class="operator">::</span>dao<span class="operator">::</span>update_by_query<span class="operator">&lt;</span>T<span class="operator">&gt;()</span>
qx<span class="operator">::</span>dao<span class="operator">::</span>delete_by_query<span class="operator">&lt;</span>T<span class="operator">&gt;()</span>
qx<span class="operator">::</span>dao<span class="operator">::</span>destroy_by_query<span class="operator">&lt;</span>T<span class="operator">&gt;()</span>
qx<span class="operator">::</span>dao<span class="operator">::</span>fetch_by_query_with_relation<span class="operator">&lt;</span>T<span class="operator">&gt;()</span>
qx<span class="operator">::</span>dao<span class="operator">::</span>fetch_by_query_with_all_relation<span class="operator">&lt;</span>T<span class="operator">&gt;()</span>
qx<span class="operator">::</span>dao<span class="operator">::</span>update_by_query_with_relation<span class="operator">&lt;</span>T<span class="operator">&gt;()</span>
qx<span class="operator">::</span>dao<span class="operator">::</span>update_by_query_with_all_relation<span class="operator">&lt;</span>T<span class="operator">&gt;()</span>
qx<span class="operator">::</span>dao<span class="operator">::</span>update_optimized_by_query<span class="operator">&lt;</span>T<span class="operator">&gt;()</span><span class="comment">
// avec la classe qx::QxSession
</span>qx<span class="operator">::</span>QxSession<span class="operator">::</span>count<span class="operator">&lt;</span>T<span class="operator">&gt;()</span>
qx<span class="operator">::</span>QxSession<span class="operator">::</span>fetchByQuery<span class="operator">&lt;</span>T<span class="operator">&gt;()</span>
qx<span class="operator">::</span>QxSession<span class="operator">::</span>update<span class="operator">&lt;</span>T<span class="operator">&gt;()</span>
qx<span class="operator">::</span>QxSession<span class="operator">::</span>deleteByQuery<span class="operator">&lt;</span>T<span class="operator">&gt;()</span>
qx<span class="operator">::</span>QxSession<span class="operator">::</span>destroyByQuery<span class="operator">&lt;</span>T<span class="operator">&gt;()</span><span class="comment">
// avec la classe qx::QxRepository&lt;T&gt;
</span>qx<span class="operator">::</span>QxRepository<span class="operator">&lt;</span>T<span class="operator">&gt;::</span>count<span class="operator">()</span>
qx<span class="operator">::</span>QxRepository<span class="operator">&lt;</span>T<span class="operator">&gt;::</span>fetchByQuery<span class="operator">()</span>
qx<span class="operator">::</span>QxRepository<span class="operator">&lt;</span>T<span class="operator">&gt;::</span>update<span class="operator">()</span>
qx<span class="operator">::</span>QxRepository<span class="operator">&lt;</span>T<span class="operator">&gt;::</span>deleteByQuery<span class="operator">()</span>
qx<span class="operator">::</span>QxRepository<span class="operator">&lt;</span>T<span class="operator">&gt;::</span>destroyByQuery<span class="operator">()</span></pre>
</td>
</tr>
</tbody>
</table>
<br>
<b>Remarque :</b> certaines de ces fonctions ont <20>galement deux autres param<61>tres optionnels :
<ul>
<li><i>const QStringList & columns</i> : pour indiquer la liste des colonnes <20> r<>cup<75>rer (par
d<>faut, toutes les colonnes sont r<>cup<75>r<EFBFBD>es) ;</li>
<li><i>const QStringList & relation</i> : pour indiquer les jointures (<i>one-to-one</i>,
<i>one-to-many</i>, <i>many-to-one</i> et <i>many-to-many</i> d<>finies dans la fonction de mapping
<i>void qx::register_class&lt;T&gt;()</i>) entre les tables de la base de donn<6E>es (par d<>faut,
aucune relation).
</li>
</ul>
</td>
</tr>
</tbody>
</table>
<br><br>
<a name="faq_220"><u><b>Comment utiliser le cache (fonctions du namespace <i>qx::cache</i>) pour stocker tous
types de donn<6E>es ?</b></u></a><br><br>
<table border="0" style="width: 100%" align="center">
<col>
<col>
<tbody>
<tr>
<td valign="middle" width="30"></td>
<td align="justify">
Le cache propos<6F> par la biblioth<74>que QxOrm (<a href="../doxygen/html/group___qx_cache.html"
target="_blank">module <i>QxCache</i></a>) est <i>thread-safe</i> et permet de stocker facilement
n'importe quel type de donn<6E>es.<br>
Les fonctions pour acc<63>der au cache se trouvent dans le <a
href="../doxygen/html/namespaceqx_1_1cache.html" target="_blank"><i>namespace</i>
<i>qx::cache</i></a>.<br>
Le cache permet une optimisation du programme : il est possible par exemple de stocker des <20>l<EFBFBD>ments
issus d'une requ<71>te effectu<74>e en base de donn<6E>es.<br>
<br>
Chaque <20>l<EFBFBD>ment stock<63> dans le cache est associ<63> <20> une cl<63> de type <i>QString</i> : cette cl<63> permet de
retrouver rapidement un <20>l<EFBFBD>ment du cache.<br>
Si un nouvel <20>l<EFBFBD>ment est stock<63> dans le cache avec une cl<63> qui existe d<>j<EFBFBD>, alors l'ancien <20>l<EFBFBD>ment
associ<63> <20> cette cl<63> est effac<61> automatiquement du cache.<br>
<br>
Le cache de la biblioth<74>que QxOrm ne g<>re pas la dur<75>e de vie des objets : il n'y a aucun
<i>delete</i> effectu<74> par le cache.<br>
C'est pourquoi il est fortement recommand<6E> (mais ce n'est pas une obligation) de privil<69>gier le
stockage de pointeurs intelligents : par exemple, <a
href="http://www.boost.org/doc/libs/release/libs/smart_ptr/shared_ptr.htm"
target="_blank"><i>boost::shared_ptr&lt;T&gt;</i></a> pour la biblioth<74>que <i>boost</i> ou bien <a
href="http://doc-snapshots.qt.io/4.8/qsharedpointer.html"
target="_blank"><i>QSharedPointer&lt;T&gt;</i></a> pour la biblioth<74>que <i>Qt</i>.<br>
<br>
Le cache peut avoir un co<63>t relatif maximum pour <20>viter une utilisation de la m<>moire trop importante
: chaque <20>l<EFBFBD>ment ins<6E>r<EFBFBD> dans le cache peut indiquer un co<63>t repr<70>sentant une estimation de sa taille
m<>moire (par exemple, le nombre d'<27>l<EFBFBD>ments d'une collection).<br>
Lorsque le co<63>t maximum du cache est atteint, les premiers <20>l<EFBFBD>ments ins<6E>r<EFBFBD>s dans le cache sont
supprim<69>s (en respectant l'ordre d'insertion dans le cache) jusqu'<27> ce que la limite du cache ne soit
plus d<>pass<73>e.<br>
<br>
Il est possible d'associer <20> chaque <20>l<EFBFBD>ment du cache une date-heure d'insertion.<br>
Si aucune date-heure n'est renseign<67>e, alors la date-heure courante est prise en compte.<br>
Ce m<>canisme permet de v<>rifier si un <20>l<EFBFBD>ment stock<63> dans le cache n<>cessite une mise <20> jour ou
non.<br>
<br>
Voici un exemple d'utilisation du cache de la biblioth<74>que QxOrm (fonctions du <a
href="../doxygen/html/namespaceqx_1_1cache.html" target="_blank"><i>namespace</i>
<i>qx::cache</i></a>) :<br>
<br>
<table border="1" bgcolor="#FFFFFF">
<col>
<tbody>
<tr>
<td>
<pre><span class="comment">// D<>fini le co<63>t maximum du cache <20> 500
</span>qx<span class="operator">::</span>cache<span class="operator">::</span>max_cost<span class="operator">(</span><span class="int">500</span><span class="operator">);</span><span class="comment">
// R<>cup<75>re une liste de 'author' de la base de donn<6E>es
</span>boost<span class="operator">::</span>shared_ptr<span class="operator">&lt;</span> QList<span class="operator">&lt;</span>author<span class="operator">&gt; &gt;</span> list_author<span class="operator">;</span>
QSqlError daoError<span class="operator"> =</span> qx<span class="operator">::</span>dao<span class="operator">::</span>fetch_all<span class="operator">(</span>list_author<span class="operator">);</span><span class="comment">
// Ins<6E>re la liste de 'author' dans le cache
</span>qx<span class="operator">::</span>cache<span class="operator">::</span>set<span class="operator">(</span><span class="string">"list_author"</span><span class="operator">,</span> list_author<span class="operator">);</span><span class="comment">
// R<>cup<75>re une liste de 'blog' de la base de donn<6E>es
</span>QSharedPointer<span class="operator">&lt;</span> std<span class="operator">::</span>vector<span class="operator">&lt;</span>blog<span class="operator">&gt; &gt;</span> list_blog<span class="operator">;</span>
daoError<span class="operator"> =</span> qx<span class="operator">::</span>dao<span class="operator">::</span>fetch_all<span class="operator">(</span>list_blog<span class="operator">);</span><span class="comment">
// Ins<6E>re la liste de 'blog' dans le cache (co<63>t = nombre de 'blog')
</span>qx<span class="operator">::</span>cache<span class="operator">::</span>set<span class="operator">(</span><span class="string">"list_blog"</span><span class="operator">,</span> list_blog<span class="operator">,</span> list_blog<span class="operator">.</span>count<span class="operator">());</span><span class="comment">
// Pointeur vers un objet de type 'comment'
</span>comment_ptr my_comment<span class="operator">;</span>
my_comment<span class="operator">.</span>reset<span class="operator">(</span><span class="keyword">new</span> comment<span class="operator">(</span><span class="int">50</span><span class="operator">));</span>
daoError<span class="operator"> =</span> qx<span class="operator">::</span>dao<span class="operator">::</span>fetch_by_id<span class="operator">(</span>my_comment<span class="operator">);</span><span class="comment">
// Ins<6E>re le 'comment' dans le cache en pr<70>cisant une date-heure d'insertion
</span>qx<span class="operator">::</span>cache<span class="operator">::</span>set<span class="operator">(</span><span class="string">"comment"</span><span class="operator">,</span> my_comment<span class="operator">,</span><span class="int"> 1</span><span class="operator">,</span> my_comment<span class="operator">-&gt;</span>dateModif<span class="operator">());</span><span class="comment">
// R<>cup<75>re la liste de 'blog' stock<63>e dans le cache
</span>list_blog<span class="operator"> =</span> qx<span class="operator">::</span>cache<span class="operator">::</span>get<span class="operator">&lt;</span> QSharedPointer<span class="operator">&lt;</span> std<span class="operator">::</span>vector<span class="operator">&lt;</span>blog<span class="operator">&gt; &gt; &gt;(</span><span class="string">"list_blog"</span><span class="operator">);</span><span class="comment">
// R<>cup<75>re la liste de 'blog' sans pr<70>ciser le type
</span>qx_bool bGetOk<span class="operator"> =</span> qx<span class="operator">::</span>cache<span class="operator">::</span>get<span class="operator">(</span><span class="string">"list_blog"</span><span class="operator">,</span> list_blog<span class="operator">);</span><span class="comment">
// Supprime du cache la liste de 'author'
</span><span class="type">bool</span> bRemoveOk<span class="operator"> =</span> qx<span class="operator">::</span>cache<span class="operator">::</span>remove<span class="operator">(</span><span class="string">"list_author"</span><span class="operator">);</span><span class="comment">
// Compte le nombre d'<27>l<EFBFBD>ments du cache
</span><span class="type">long</span> lCount<span class="operator"> =</span> qx<span class="operator">::</span>cache<span class="operator">::</span>count<span class="operator">();</span><span class="comment">
// R<>cup<75>re le co<63>t actuel des <20>l<EFBFBD>ments stock<63>s dans le cache
</span><span class="type">long</span> lCurrentCost<span class="operator"> =</span> qx<span class="operator">::</span>cache<span class="operator">::</span>current_cost<span class="operator">();</span><span class="comment">
// V<>rifie qu'un <20>l<EFBFBD>ment associ<63> <20> la cl<63> "comment" existe dans le cache
</span><span class="type">bool</span> bExist<span class="operator"> =</span> qx<span class="operator">::</span>cache<span class="operator">::</span>exist<span class="operator">(</span><span class="string">"comment"</span><span class="operator">);</span><span class="comment">
// R<>cup<75>re le 'comment' stock<63> dans le cache avec sa date-heure d'insertion
</span>QDateTime dt<span class="operator">;</span>
bGetOk<span class="operator"> =</span> qx<span class="operator">::</span>cache<span class="operator">::</span>get<span class="operator">(</span><span class="string">"comment"</span><span class="operator">,</span> my_comment<span class="operator">,</span> dt<span class="operator">);</span><span class="comment">
// Vide le cache
</span>qx<span class="operator">::</span>cache<span class="operator">::</span>clear<span class="operator">();</span></pre>
</td>
</tr>
</tbody>
</table>
<br>
</td>
</tr>
</tbody>
</table>
<br><br>
<a name="faq_230"><u><b>Comment g<>n<EFBFBD>rer le sch<63>ma SQL (cr<63>ation et mise <20> jour des tables) en fonction des
classes persistantes C++ d<>finies dans le contexte QxOrm ?</b></u></a><br><br>
<table border="0" style="width: 100%" align="center">
<col>
<col>
<tbody>
<tr>
<td valign="middle" width="30"></td>
<td align="justify">
<a href="#faq_15">Il est recommand<6E> d'utiliser l'application <b>QxEntityEditor</b> pour g<>rer cette
probl<62>matique.</a><br>
<br>
La biblioth<74>que QxOrm ne fournit pas de m<>canisme pour g<>rer automatiquement la cr<63>ation et mise <20>
jour des tables dans la base de donn<6E>es.<br>
En effet, la fonction <i>qx::dao::create_table&lt;T&gt;</i> doit <20>tre utilis<69>e uniquement pour cr<63>er
des prototypes.<br>
Il est fortement recommand<6E> d'utiliser un outil sp<73>cifique <20> chaque SGBD pour cr<63>er et maintenir les
tables de la base de donn<6E>es (par exemple <i>Navicat</i> pour <i>MySql</i>, <i>pgAdmin</i> pour
<i>PostgreSQL</i>, <i>SQLite Manager</i> pour <i>SQLite</i>, etc.).<br>
De plus, un outil sp<73>cifique <20> chaque SGBD permet d'appliquer certaines optimisations (ajout d'index
par exemple).<br>
<br>
Cependant, il peut <20>tre int<6E>ressant pour certaines applications de ne pas avoir <20> g<>rer manuellement
les tables de la base de donn<6E>es.<br>
Dans ce cas, il est possible de cr<63>er une fonction C++ pour parcourir la liste des classes
persistantes enregistr<74>es dans le contexte QxOrm (en utilisant le moteur d'introspection de la
biblioth<74>que) et ainsi cr<63>er un script SQL de g<>n<EFBFBD>ration et mise <20> jour des tables de la base de
donn<6E>es.<br>
<br>
La biblioth<74>que QxOrm fournit une fonction C++ cr<63><72>e uniquement <20> titre d'exemple : elle peut donc
servir de base de travail pour cr<63>er sa propre fonction de g<>n<EFBFBD>ration de script SQL.<br>
Cette fonction se trouve dans le fichier <i><a href="./resource/qxclassx_dump_sql_schema.html"
target="_blank">./src/QxRegister/QxClassX.cpp</a></i> et se nomme <i><a
href="./resource/qxclassx_dump_sql_schema.html" target="_blank">QString
qx::QxClassX::dumpSqlSchema()</a></i>.<br>
Elle g<>n<EFBFBD>re un script SQL et le renvoie sous forme de <i>QString</i> : il est possible d'adapter cette
fonction pour g<>n<EFBFBD>rer un fichier contenant le script SQL ou bien appliquer chaque instruction SQL
directement au SGBD.<br>
<br>
Voici un exemple d'impl<70>mentation propos<6F> par <a
href="http://www.developpez.net/forums/u449556/dodobibi/" target="_blank">dodobibi</a> pour g<>rer
une base <i>PostgreSQL</i> : cet exemple g<>re les <20>volutions futures de son application (ajout de
colonnes dans une table existante, ajout d'index sur une colonne existante, etc.).<br>
Au lancement de l'application, le num<75>ro de version est indiqu<71> de la fa<66>on suivante :<br>
<br>
<table border="1" bgcolor="#FFFFFF">
<col>
<tbody>
<tr>
<td>
<pre>QApplication app<span class="operator">(</span>argc<span class="operator">,</span> argv<span class="operator">);</span>
app<span class="operator">.</span>setProperty<span class="operator">(</span><span class="string">"DomainVersion"</span><span class="operator">,</span><span class="int"> 1</span><span class="operator">);</span><span class="comment"> // Version increment<6E>e <20> chaque compilation et diffusion de l'application</span></pre>
</td>
</tr>
</tbody>
</table>
<br>
Une table de la base de donn<6E>es permet de stocker le num<75>ro de version courant.<br>
Une classe persistante C++ est mapp<70>e sur cette table de la fa<66>on suivante :<br>
<br>
<table border="1" bgcolor="#FFFFFF">
<col>
<tbody>
<tr>
<td>
<pre><span class="pre">#ifndef _DATABASE_VERSION_H_
#define _DATABASE_VERSION_H_
</span><span class="keyword">
class</span> MY_DLL_EXPORT DatabaseVersion<span class="operator">
{</span><span class="keyword">
public</span><span class="operator">:</span>
QString name<span class="operator">;</span><span class="type">
long</span> version<span class="operator">;
};</span>
QX_REGISTER_HPP_MY_APP<span class="operator">(</span>DatabaseVersion<span class="operator">,</span> qx<span class="operator">::</span>trait<span class="operator">::</span>no_base_class_defined<span class="operator">,</span><span class="int"> 0</span><span class="operator">)</span><span class="pre">
#endif // _DATABASE_VERSION_H_</span></pre>
</td>
</tr>
</tbody>
</table>
<br>
<table border="1" bgcolor="#FFFFFF">
<col>
<tbody>
<tr>
<td>
<pre><span class="pre">#include "../include/precompiled.h"
#include "../include/DatabaseVersion.h"
#include &lt;QxOrm_Impl.h&gt;
</span>
QX_REGISTER_CPP_MY_APP<span class="operator">(</span>DatabaseVersion<span class="operator">)</span><span class="keyword">
namespace</span> qx<span class="operator"> {</span><span class="keyword">
template</span><span class="operator"> &lt;&gt;</span><span class="type"> void</span> register_class<span class="operator">(</span>QxClass<span class="operator">&lt;</span>DatabaseVersion<span class="operator">&gt; &amp;</span> t<span class="operator">)
{</span>
t<span class="operator">.</span>id<span class="operator">(&amp;</span> DatabaseVersion<span class="operator">::</span>name<span class="operator">,</span><span class="string"> "name"</span><span class="operator">);</span>
t<span class="operator">.</span>data<span class="operator">(&amp;</span> DatabaseVersion<span class="operator">::</span>version<span class="operator">,</span><span class="string"> "version"</span><span class="operator">);
}}</span></pre>
</td>
</tr>
</tbody>
</table>
<br>
Avec la classe <i>DatabaseVersion</i>, il est possible de v<>rifier si la version de la base de donn<6E>es
est <20> jour.<br>
C'est le r<>le de la fonction <i>isDatabaseVersionOld()</i> :<br>
<br>
<table border="1" bgcolor="#FFFFFF">
<col>
<tbody>
<tr>
<td>
<pre><span class="type">bool</span> isDatabaseVersionOld<span class="operator">()
{</span>
DatabaseVersion dbVersion<span class="operator">;</span>
dbVersion<span class="operator">.</span>name<span class="operator"> =</span><span class="string"> "MyAppName"</span><span class="operator">;</span>
QSqlError err<span class="operator"> =</span> qx<span class="operator">::</span>dao<span class="operator">::</span>fetch_by_id<span class="operator">(</span>dbVersion<span class="operator">);</span><span class="flow">
if</span><span class="operator"> (</span>err<span class="operator">.</span>isValid<span class="operator">()) {</span> qAssert<span class="operator">(</span><span class="bool">false</span><span class="operator">);</span><span class="flow"> return</span><span class="bool"> false</span><span class="operator">; }</span><span class="flow">
return</span><span class="operator"> (</span>dbVersion<span class="operator">.</span>version<span class="operator"> &lt;</span> qApp<span class="operator">-&gt;</span>property<span class="operator">(</span><span class="string">"DomainVersion"</span><span class="operator">).</span>toInt<span class="operator">());
}</span></pre>
</td>
</tr>
</tbody>
</table>
<br>
Si au lancement de l'application, la fonction <i>isDatabaseVersionOld()</i> renvoie <i>true</i>, alors
la mise <20> jour de la base de donn<6E>es est effectu<74>e de la fa<66>on suivante :<br>
<br>
<table border="1" bgcolor="#FFFFFF">
<col>
<tbody>
<tr>
<td>
<pre><span class="type">void</span> updateDatabaseVersion<span class="operator">()
{</span><span class="flow">
try</span><span class="operator">
{</span><span class="type">
int</span> domainVersion<span class="operator"> =</span> qApp<span class="operator">-&gt;</span>property<span class="operator">(</span><span class="string">"DomainVersion"</span><span class="operator">).</span>toInt<span class="operator">();</span><span class="comment">
// On se connecte avec un utilisateur de la base de donn<6E>es qui a les droits de modifications du sch<63>ma
</span> QSqlDatabase db<span class="operator"> =</span> qx<span class="operator">::</span>QxSqlDatabase<span class="operator">::</span>getSingleton<span class="operator">()-&gt;</span>getDatabaseCloned<span class="operator">();</span>
db<span class="operator">.</span>setUserName<span class="operator">(</span><span class="string">"MyAdminLogin"</span><span class="operator">);</span>
db<span class="operator">.</span>setPassword<span class="operator">(</span><span class="string">"MyAdminPassword"</span><span class="operator">);</span><span class="comment">
// On s'assure que la session d<>marre une transaction et l<>ve une exception <20> la moindre erreur
</span> qx<span class="operator">::</span>QxSession session<span class="operator">(</span>db<span class="operator">,</span><span class="bool"> true</span><span class="operator">,</span><span class="bool"> true</span><span class="operator">);</span><span class="comment">
// On "fetch" la version de la base de donn<6E>es avec un verrou pour <20>viter les modifications concurrentes !
// Si plusieurs utilisateurs lancent l'application en m<>me temps et qu'une mise <20> jour
// est n<>cessaire, le premier fera la mise <20> jour, et les autres seront en attente
</span> DatabaseVersion dbVersion<span class="operator">;</span>
session<span class="operator">.</span>fetchByQuery<span class="operator">(</span>qx_query<span class="operator">(</span><span class="string">"WHERE name='MyAppName' FOR UPDATE"</span><span class="operator">),</span> dbVersion<span class="operator">);</span><span class="comment">
// Pour les autres utilisateurs, une fois le verrou lev<65>, on v<>rifie si la mise <20> jour est toujours n<>cessaire
</span><span class="flow"> if</span><span class="operator"> (</span>dbVersion<span class="operator">.</span>version<span class="operator"> &gt;=</span> domainVersion<span class="operator">) {</span><span class="flow"> return</span><span class="operator">; }</span><span class="comment">
// On ex<65>cute chaque instruction SQL avec la variable "query"
</span> QSqlQuery query<span class="operator">(</span>db<span class="operator">);</span><span class="comment">
// On r<>cup<75>re toutes les classes persistantes C++ enregistr<74>es dans le contexte QxOrm
</span> qx<span class="operator">::</span>QxCollection<span class="operator">&lt;</span>QString<span class="operator">,</span> qx<span class="operator">::</span>IxClass<span class="operator"> *&gt; *</span> pAllClasses<span class="operator"> =</span> qx<span class="operator">::</span>QxClassX<span class="operator">::</span>getAllClasses<span class="operator">();</span><span class="flow">
if</span><span class="operator"> (!</span> pAllClasses<span class="operator">) {</span> qAssert<span class="operator">(</span><span class="bool">false</span><span class="operator">);</span><span class="flow"> return</span><span class="operator">; }</span><span class="comment">
// on r<>cup<75>re la liste des tables existantes dans la base (fonction de Qt)
</span> QStringList tables<span class="operator"> =</span> db<span class="operator">.</span>tables<span class="operator">();</span><span class="flow">
for</span><span class="operator"> (</span><span class="type">long</span> k<span class="operator"> =</span><span class="int"> 0</span><span class="operator">;</span> k<span class="operator"> &lt;</span> pAllClasses<span class="operator">-&gt;</span>count<span class="operator">();</span> k<span class="operator">++)
{</span>
qx<span class="operator">::</span>IxClass<span class="operator"> *</span> pClass<span class="operator"> =</span> pAllClasses<span class="operator">-&gt;</span>getByIndex<span class="operator">(</span>k<span class="operator">);</span><span class="flow">
if</span><span class="operator"> (!</span> pClass<span class="operator">) {</span><span class="flow"> continue</span><span class="operator">; }</span><span class="comment">
// Filtre les classes non persistantes
</span><span class="flow"> if</span><span class="operator"> (</span>pClass<span class="operator">-&gt;</span>isKindOf<span class="operator">(</span><span class="string">"qx::service::IxParameter"</span><span class="operator">) ||</span> pClass<span class="operator">-&gt;</span>isKindOf<span class="operator">(</span><span class="string">"qx::service::IxService"</span><span class="operator">)) {</span><span class="flow"> continue</span><span class="operator">; }</span><span class="comment">
// Filtre les classes <20> jour : si la version de pClass est &lt;= <20> la version enregistr<74>e dans la base, la mise <20> jour n'est pas n<>cessaire
</span><span class="flow"> if</span><span class="operator"> (</span>pClass<span class="operator">-&gt;</span>getVersion<span class="operator">() &lt;=</span> dbVersion<span class="operator">.</span>version<span class="operator">) {</span><span class="flow"> continue</span><span class="operator">; }</span><span class="comment">
// On cr<63>e la table si elle n'existe pas, et on d<>finit son propri<72>taire
</span><span class="flow"> if</span><span class="operator"> (!</span> tables<span class="operator">.</span>contains<span class="operator">(</span>pClass<span class="operator">-&gt;</span>getName<span class="operator">()))
{</span>
query<span class="operator">.</span>exec<span class="operator">(</span><span class="string">"CREATE TABLE "</span><span class="operator"> +</span> pClass<span class="operator">-&gt;</span>getName<span class="operator">() +</span><span class="string"> " ( ) WITH (OIDS = FALSE);"
"ALTER TABLE "</span><span class="operator"> +</span> pClass<span class="operator">-&gt;</span>getName<span class="operator">() +</span><span class="string"> " OWNER TO \"MyAdminLogin\";"</span><span class="operator">);</span>
session<span class="operator"> +=</span> query<span class="operator">.</span>lastError<span class="operator">();
}</span><span class="comment">
// On ajoute les colonnes <20> la table si elles n'existent pas
</span> qx<span class="operator">::</span>IxDataMemberX<span class="operator"> *</span> pDataMemberX<span class="operator"> =</span> pClass<span class="operator">-&gt;</span>getDataMemberX<span class="operator">();</span><span class="flow">
for</span><span class="operator"> (</span><span class="type">long</span> l<span class="operator"> =</span><span class="int"> 0</span><span class="operator">; (</span>pDataMemberX<span class="operator"> &amp;&amp; (</span>l<span class="operator"> &lt;</span> pDataMemberX<span class="operator">-&gt;</span>count_WithDaoStrategy<span class="operator">()));</span> l<span class="operator">++)
{</span>
qx<span class="operator">::</span>IxDataMember<span class="operator"> *</span> p<span class="operator"> =</span> pDataMemberX<span class="operator">-&gt;</span>get_WithDaoStrategy<span class="operator">(</span>l<span class="operator">);</span><span class="flow">
if</span><span class="operator"> (!</span> p<span class="operator"> || (</span>p<span class="operator">-&gt;</span>getVersion<span class="operator">() &lt;=</span> dbVersion<span class="operator">.</span>version<span class="operator">)) {</span><span class="flow"> continue</span><span class="operator">; }</span>
query<span class="operator">.</span>exec<span class="operator">(</span><span class="string">"ALTER TABLE "</span><span class="operator"> +</span> pClass<span class="operator">-&gt;</span>getName<span class="operator">() +</span><span class="string"> " ADD COLUMN "</span><span class="operator"> +</span> p<span class="operator">-&gt;</span>getName<span class="operator">() +</span><span class="string"> " "</span><span class="operator"> +</span> p<span class="operator">-&gt;</span>getSqlType<span class="operator">() +</span><span class="string"> ";"</span><span class="operator">);</span>
session<span class="operator"> +=</span> query<span class="operator">.</span>lastError<span class="operator">();</span><span class="flow">
if</span><span class="operator"> (</span>p<span class="operator">-&gt;</span>getIsPrimaryKey<span class="operator">())</span><span class="comment"> // PRIMARY KEY
</span><span class="operator"> {</span>
query<span class="operator">.</span>exec<span class="operator">(</span><span class="string">"ALTER TABLE "</span><span class="operator"> +</span> pClass<span class="operator">-&gt;</span>getName<span class="operator">() +</span><span class="string"> " ADD PRIMARY KEY ("</span><span class="operator"> +</span> p<span class="operator">-&gt;</span>getName<span class="operator">() +</span><span class="string"> ");"</span><span class="operator">);</span>
session<span class="operator"> +=</span> query<span class="operator">.</span>lastError<span class="operator">();
}</span><span class="flow">
if</span><span class="operator"> (</span>p<span class="operator">-&gt;</span>getAllPropertyBagKeys<span class="operator">().</span>contains<span class="operator">(</span><span class="string">"INDEX"</span><span class="operator">))</span><span class="comment"> // INDEX
</span><span class="operator"> {</span>
query<span class="operator">.</span>exec<span class="operator">(</span><span class="string">"CREATE INDEX "</span><span class="operator"> +</span> pClass<span class="operator">-&gt;</span>getName<span class="operator">() +</span><span class="string"> "_"</span><span class="operator"> +</span> p<span class="operator">-&gt;</span>getName<span class="operator">() +</span><span class="string"> "_idx"</span><span class="operator"> +</span><span class="string">
" ON "</span><span class="operator"> +</span> pClass<span class="operator">-&gt;</span>getName<span class="operator">() +</span><span class="string"> " USING "</span><span class="operator"> +</span> p<span class="operator">-&gt;</span>getPropertyBag<span class="operator">(</span><span class="string">"INDEX"</span><span class="operator">).</span>toString<span class="operator">() +</span><span class="string"> " ("</span><span class="operator"> +</span> p<span class="operator">-&gt;</span>getName<span class="operator">() +</span><span class="string"> ");"</span><span class="operator">);</span>
session<span class="operator"> +=</span> query<span class="operator">.</span>lastError<span class="operator">();
}</span><span class="flow">
if</span><span class="operator"> (</span>p<span class="operator">-&gt;</span>getNotNull<span class="operator">())</span><span class="comment"> // NOT NULL
</span><span class="operator"> {</span>
query<span class="operator">.</span>exec<span class="operator">(</span><span class="string">"ALTER TABLE "</span><span class="operator"> +</span> pClass<span class="operator">-&gt;</span>getName<span class="operator">() +</span><span class="string"> " ALTER COLUMN "</span><span class="operator"> +</span> p<span class="operator">-&gt;</span>getName<span class="operator">() +</span><span class="string"> " SET NOT NULL;"</span><span class="operator">);</span>
session<span class="operator"> +=</span> query<span class="operator">.</span>lastError<span class="operator">();
}</span><span class="flow">
if</span><span class="operator"> (</span>p<span class="operator">-&gt;</span>getAutoIncrement<span class="operator">())</span><span class="comment"> // AUTO INCREMENT
</span><span class="operator"> {</span>
query<span class="operator">.</span>exec<span class="operator">(</span><span class="string">"CREATE SEQUENCE "</span><span class="operator"> +</span> pClass<span class="operator">-&gt;</span>getName<span class="operator">() +</span><span class="string"> "_"</span><span class="operator"> +</span> p<span class="operator">-&gt;</span>getName<span class="operator">() +</span><span class="string"> "_seq"</span><span class="operator"> +</span><span class="string"> "; "
"ALTER TABLE "</span><span class="operator"> +</span> pClass<span class="operator">-&gt;</span>getName<span class="operator">() +</span><span class="string"> "_"</span><span class="operator"> +</span> p<span class="operator">-&gt;</span>getName<span class="operator">() +</span><span class="string"> "_seq"</span><span class="operator"> +</span><span class="string"> " OWNER TO \"MyAdminLogin\"; "
"ALTER TABLE "</span><span class="operator"> +</span> pClass<span class="operator">-&gt;</span>getName<span class="operator">() +</span><span class="string"> " ALTER COLUMN "</span><span class="operator"> +</span> p<span class="operator">-&gt;</span>getName<span class="operator">() +</span><span class="string"> " "</span><span class="operator"> +</span><span class="string">
"SET DEFAULT nextval('"</span><span class="operator"> +</span> pClass<span class="operator">-&gt;</span>getName<span class="operator">() +</span><span class="string"> "_"</span><span class="operator"> +</span> p<span class="operator">-&gt;</span>getName<span class="operator">() +</span><span class="string"> "_seq"</span><span class="operator"> +</span><span class="string"> "'::regclass);"</span><span class="operator">);</span>
session<span class="operator"> +=</span> query<span class="operator">.</span>lastError<span class="operator">();
}</span><span class="flow">
if</span><span class="operator"> (</span>p<span class="operator">-&gt;</span>getDescription<span class="operator">() !=</span><span class="string"> ""</span><span class="operator">)</span><span class="comment"> // DESCRIPTION
</span><span class="operator"> {</span><span class="comment">
// $$ceci est un texte ne n<>cessitant pas de caract<63>res d'<27>chappement dans postgres grace aux doubles dolars$$
</span> query<span class="operator">.</span>exec<span class="operator">(</span><span class="string">"COMMENT ON COLUMN "</span><span class="operator"> +</span> pClass<span class="operator">-&gt;</span>getName<span class="operator">() +</span><span class="string"> "."</span><span class="operator"> +</span> p<span class="operator">-&gt;</span>getName<span class="operator">() +</span><span class="string"> " IS $$"</span><span class="operator"> +</span> p<span class="operator">-&gt;</span>getDescription<span class="operator">() +</span><span class="string"> "$$ ;"</span><span class="operator">);</span>
session<span class="operator"> +=</span> query<span class="operator">.</span>lastError<span class="operator">();
}
}
}</span><span class="comment">
// On enregistre la version courante de la base de donn<6E>es
</span> dbVersion<span class="operator">.</span>version<span class="operator"> =</span> domainVersion<span class="operator">;</span>
session<span class="operator">.</span>save<span class="operator">(</span>dbVersion<span class="operator">);</span><span class="comment">
// Fin du block "try" : la session est d<>truite =&gt; commit ou rollback automatique
// De plus, un commit ou rollback sur la transaction l<>ve automatiquement le verrou pos<6F> pr<70>c<EFBFBD>demment
</span><span class="operator"> }</span><span class="flow">
catch</span><span class="operator"> (</span><span class="keyword">const</span> qx<span class="operator">::</span>dao<span class="operator">::</span>sql_error<span class="operator"> &amp;</span> err<span class="operator">)
{</span>
QSqlError sqlError<span class="operator"> =</span> err<span class="operator">.</span>get<span class="operator">();</span>
qDebug<span class="operator">() &lt;&lt;</span> sqlError<span class="operator">.</span>databaseText<span class="operator">();</span>
qDebug<span class="operator">() &lt;&lt;</span> sqlError<span class="operator">.</span>driverText<span class="operator">();</span>
qDebug<span class="operator">() &lt;&lt;</span> sqlError<span class="operator">.</span>number<span class="operator">();</span>
qDebug<span class="operator">() &lt;&lt;</span> sqlError<span class="operator">.</span>type<span class="operator">();
}
}</span></pre>
</td>
</tr>
</tbody>
</table>
<br>
<b>Remarque :</b> le code pr<70>c<EFBFBD>dent (tout comme la fonction <a
href="./resource/qxclassx_dump_sql_schema.html"
target="_blank"><i>qx::QxClassX::dumpSqlSchema()</i></a>) peut <20>tre modifi<66> pour s'adapter aux
besoins sp<73>cifiques d'une application.<br>
Par exemple, il pourrait <20>tre int<6E>ressant de cr<63>er par d<>faut une seconde table (en plus de la table
<i>DatabaseVersion</i>) pour enregistrer la liste des classes persistantes enregistr<74>es dans le
contexte QxOrm : ainsi, au lieu d'utiliser la fonction propos<6F>e par Qt "<i>db.tables()</i>", il serait
possible de r<>cup<75>rer toutes les tables mapp<70>es sur des classes persistantes avec des informations
suppl<70>mentaires (num<75>ro de version pour chaque table, nombre de colonnes enregistr<74>es dans le contexte
QxOrm, description de chaque table, etc.).
<br>
</td>
</tr>
</tbody>
</table>
<br><br>
<a name="faq_240"><u><b>Comment associer un type SQL <20> une classe C++ ?</b></u></a><br><br>
<table border="0" style="width: 100%" align="center">
<col>
<col>
<tbody>
<tr>
<td valign="middle" width="30"></td>
<td align="justify">
Chaque base de donn<6E>es propose des types SQL diff<66>rents pour stocker l'information.<br>
La biblioth<74>que QxOrm propose une association par d<>faut pour les classes C++ les plus fr<66>quemment
utilis<69>es dans un programme.<br>
Voici cette association par d<>faut :<br>
<br>
<table border="1" bgcolor="#FFFFFF">
<col>
<tbody>
<tr>
<td>
<pre><span class="string">"bool"</span><span class="operator"> &lt;-&gt;</span><span class="string"> "SMALLINT"
"qx_bool"</span><span class="operator"> &lt;-&gt;</span><span class="string"> "SMALLINT"
"short"</span><span class="operator"> &lt;-&gt;</span><span class="string"> "SMALLINT"
"int"</span><span class="operator"> &lt;-&gt;</span><span class="string"> "INTEGER"
"long"</span><span class="operator"> &lt;-&gt;</span><span class="string"> "INTEGER"
"long long"</span><span class="operator"> &lt;-&gt;</span><span class="string"> "INTEGER"
"float"</span><span class="operator"> &lt;-&gt;</span><span class="string"> "FLOAT"
"double"</span><span class="operator"> &lt;-&gt;</span><span class="string"> "FLOAT"
"long double"</span><span class="operator"> &lt;-&gt;</span><span class="string"> "FLOAT"
"unsigned short"</span><span class="operator"> &lt;-&gt;</span><span class="string"> "SMALLINT"
"unsigned int"</span><span class="operator"> &lt;-&gt;</span><span class="string"> "INTEGER"
"unsigned long"</span><span class="operator"> &lt;-&gt;</span><span class="string"> "INTEGER"
"unsigned long long"</span><span class="operator"> &lt;-&gt;</span><span class="string"> "INTEGER"
"std::string"</span><span class="operator"> &lt;-&gt;</span><span class="string"> "TEXT"
"std::wstring"</span><span class="operator"> &lt;-&gt;</span><span class="string"> "TEXT"
"QString"</span><span class="operator"> &lt;-&gt;</span><span class="string"> "TEXT"
"QVariant"</span><span class="operator"> &lt;-&gt;</span><span class="string"> "TEXT"
"QUuid"</span><span class="operator"> &lt;-&gt;</span><span class="string"> "TEXT"
"QDate"</span><span class="operator"> &lt;-&gt;</span><span class="string"> "DATE"
"QTime"</span><span class="operator"> &lt;-&gt;</span><span class="string"> "TIME"
"QDateTime"</span><span class="operator"> &lt;-&gt;</span><span class="string"> "TIMESTAMP"
"QByteArray"</span><span class="operator"> &lt;-&gt;</span><span class="string"> "BLOB"
"qx::QxDateNeutral"</span><span class="operator"> &lt;-&gt;</span><span class="string"> "TEXT"
"qx::QxTimeNeutral"</span><span class="operator"> &lt;-&gt;</span><span class="string"> "TEXT"
"qx::QxDateTimeNeutral"</span><span class="operator"> &lt;-&gt;</span><span class="string"> "TEXT"</span></pre>
</td>
</tr>
</tbody>
</table>
<br>
Si le type SQL propos<6F> par d<>faut par la biblioth<74>que QxOrm ne correspond pas <20> la base de donn<6E>es
utilis<69>e, il peut facilement <20>tre modifi<66> (de mani<6E>re globale <20> toute l'application) en utilisant la
collection suivante :<br>
<br>
<table border="1" bgcolor="#FFFFFF">
<col>
<tbody>
<tr>
<td>
<pre>QHash<span class="operator">&lt;</span>QString<span class="operator">,</span> QString<span class="operator">&gt; *</span> lstSqlType<span class="operator"> =</span> qx<span class="operator">::</span>QxClassX<span class="operator">::</span>getAllSqlTypeByClassName<span class="operator">();</span>
lstSqlType<span class="operator">-&gt;</span>insert<span class="operator">(</span><span class="string">"QString"</span><span class="operator">,</span><span class="string"> "VARCHAR(255)"</span><span class="operator">);</span>
lstSqlType<span class="operator">-&gt;</span>insert<span class="operator">(</span><span class="string">"std::string"</span><span class="operator">,</span><span class="string"> "VARCHAR(255)"</span><span class="operator">);</span><span class="comment">
// etc.</span></pre>
</td>
</tr>
</tbody>
</table>
<br>
Pour modifier le type SQL de mani<6E>re sp<73>cifique pour une colonne d'une table de la base de donn<6E>es, il
faut d<>finir le type SQL dans la fonction de mapping de QxOrm :<br>
<br>
<table border="1" bgcolor="#FFFFFF">
<col>
<tbody>
<tr>
<td>
<pre><span class="keyword">namespace</span> qx<span class="operator"> {</span><span class="keyword">
template</span><span class="operator"> &lt;&gt;</span><span class="type"> void</span> register_class<span class="operator">(</span>QxClass<span class="operator">&lt;</span>MyClass<span class="operator">&gt; &amp;</span> t<span class="operator">)
{</span><span class="comment">
//...
</span> IxDataMember<span class="operator"> *</span> p<span class="operator"> =</span> t<span class="operator">.</span>data<span class="operator">(&amp;</span> MyClass<span class="operator">::</span>m_MyProperty<span class="operator">,</span><span class="string"> "my_property"</span><span class="operator">);</span>
p<span class="operator">-&gt;</span>setSqlType<span class="operator">(</span><span class="string">"VARCHAR(255)"</span><span class="operator">);</span><span class="comment">
//...
</span><span class="operator">}}</span></pre>
</td>
</tr>
</tbody>
</table>
<br>
Pour les classes non support<72>es par d<>faut par la biblioth<74>que QxOrm (voir cette
<i>Question-R<>ponse</i> de la FAQ : <i><a href="./faq.html#faq_180">Comment persister un type dont on
ne poss<73>de pas le code source (classe provenant d'une biblioth<74>que tierce par exemple) ?</a></i>),
il est possible d'associer un type SQL par d<>faut en utilisant la macro suivante (en dehors de tout
<i>namespace</i>) :<br>
<br>
<table border="1" bgcolor="#FFFFFF">
<col>
<tbody>
<tr>
<td>
<pre>QX_REGISTER_TRAIT_GET_SQL_TYPE<span class="operator">(</span>MyClass<span class="operator">,</span><span class="string"> "my_sql_type"</span><span class="operator">)</span></pre>
</td>
</tr>
</tbody>
</table>
<br>
</td>
</tr>
</tbody>
</table>
<br><br>
<a name="faq_250"><u><b>Comment utiliser le module <i>QxValidator</i> pour valider automatiquement les donn<6E>es
?</b></u></a><br><br>
<table border="0" style="width: 100%" align="center">
<col>
<col>
<tbody>
<tr>
<td valign="middle" width="30"></td>
<td align="justify">
Le module <b><a href="../doxygen/html/group___qx_validator.html" target="_blank">QxValidator</a></b>
de la biblioth<74>que <b>QxOrm</b> permet d'ajouter des contraintes sur les propri<72>t<EFBFBD>s enregistr<74>es dans
le contexte QxOrm.<br>
Ces contraintes sont d<>finies dans la m<>thode de mapping : <i>void
qx::register_class&lt;T&gt;</i>.<br>
Si pour une instance de classe donn<6E>e, au moins une contrainte n'est pas respect<63>e, alors l'instance
est consid<69>r<EFBFBD>e comme invalide : l'objet ne peut alors pas <20>tre sauvegard<72> en base de donn<6E>es
(<i>INSERT</i> ou <i>UPDATE</i>).<br>
<br>
Il est <20>galement possible d'utiliser le module <b>QxValidator</b> pour valider les donn<6E>es au niveau
de la couche pr<70>sentation de l'application : si les donn<6E>es saisies par un utilisateur ne sont pas
valides, un message d'erreur peut <20>tre signal<61>, il n'est alors pas n<>cessaire d'essayer d'enregistrer
l'instance courante en base de donn<6E>es.<br>
Les r<>gles de validation n'ont pas besoin d'<27>tre dupliqu<71>es : elles peuvent <20>tre utilis<69>es aussi bien
par la couche pr<70>sentation que par la couche d'acc<63>s aux donn<6E>es de l'application.<br>
<br>
Voici la description de quelques classes du module <b>QxValidator</b> :
<ul>
<li><a href="../doxygen/html/classqx_1_1_ix_validator.html" target="_blank">qx::IxValidator</a> :
chaque contrainte d<>finie dans la fonction de mapping <i>void qx::register_class&lt;T&gt;</i> est
associ<63>e <20> une interface de type <i>qx::IxValidator</i> ;</li>
<li><a href="../doxygen/html/classqx_1_1_ix_validator_x.html" target="_blank">qx::IxValidatorX</a> :
pour une classe donn<6E>e, la liste des contraintes est associ<63>e <20> une interface de type
<i>qx::IxValidatorX</i>. Cette collection peut <20>tre parcourue <20> l'ex<65>cution du programme : <20>a peut
<20>tre int<6E>ressant par exemple pour g<>n<EFBFBD>rer le sch<63>ma SQL et prendre en compte les contraintes au
niveau de la base de donn<6E>es (voir la Q&R de la FAQ : <a href="./faq.html#faq_230"
target="_blank">Comment g<>n<EFBFBD>rer le sch<63>ma SQL (cr<63>ation et mise <20> jour des tables) en fonction
des classes persistantes C++ d<>finies dans le contexte QxOrm ?</a>) ;
</li>
<li><a href="../doxygen/html/classqx_1_1_qx_invalid_value_x.html"
target="_blank">qx::QxInvalidValueX</a> : au moment du processus de validation, lorsqu'une
instance n'est pas valide, la liste des contraintes non respect<63>es est repr<70>sent<6E>e par une
collection de type <i>qx::QxInvalidValueX</i> ;</li>
<li><a href="../doxygen/html/classqx_1_1_qx_invalid_value.html"
target="_blank">qx::QxInvalidValue</a> : chaque <20>l<EFBFBD>ment de cette collection est de type
<i>qx::QxInvalidValue</i> et contient un message d'erreur (description expliquant pourquoi
l'instance est invalide).
</li>
</ul>
Le module <b>QxValidator</b> g<>re automatiquement la notion d'h<>ritage de classe : si des contraintes
sont d<>finies au niveau de la classe de base, alors elles seront automatiquement v<>rifi<66>es pour chaque
validation d'une classe d<>riv<69>e.<br>
<br>
Voici un exemple d'utilisation du module <b>QxValidator</b> avec une classe '<i>person</i>' :<br>
<br>
* fichier '<i>person.h</i>' :<br>
<table border="1" bgcolor="#FFFFFF">
<col>
<tbody>
<tr>
<td>
<pre><span class="pre">#ifndef _CLASS_PERSON_H_
#define _CLASS_PERSON_H_
</span><span class="keyword">
class</span> person<span class="operator">
{</span><span class="keyword">
public</span><span class="operator">:</span><span class="keyword">
enum</span> sex<span class="operator"> {</span> male<span class="operator">,</span> female<span class="operator">,</span> unknown<span class="operator"> };</span><span class="type">
long</span> _id<span class="operator">;</span>
QString _firstName<span class="operator">;</span>
QString _lastName<span class="operator">;</span>
QDateTime _birthDate<span class="operator">;</span>
sex _sex<span class="operator">;</span>
person<span class="operator">() :</span> _id<span class="operator">(</span><span class="int">0</span><span class="operator">),</span> _sex<span class="operator">(</span>unknown<span class="operator">) { ; }</span>
person<span class="operator">(</span><span class="type">long</span> id<span class="operator">) :</span> _id<span class="operator">(</span>id<span class="operator">),</span> _sex<span class="operator">(</span>unknown<span class="operator">) { ; }</span><span class="keyword">
virtual</span><span class="operator"> ~</span>person<span class="operator">() { ; }</span><span class="keyword">
private</span><span class="operator">:</span><span class="type">
void</span> isValid<span class="operator">(</span>qx<span class="operator">::</span>QxInvalidValueX<span class="operator"> &amp;</span> invalidValues<span class="operator">);
};</span>
QX_REGISTER_HPP_MY_EXE<span class="operator">(</span>person<span class="operator">,</span> qx<span class="operator">::</span>trait<span class="operator">::</span>no_base_class_defined<span class="operator">,</span><span class="int"> 0</span><span class="operator">)</span><span class="pre">
#endif // _CLASS_PERSON_H_</span></pre>
</td>
</tr>
</tbody>
</table>
<br>
* fichier '<i>person.cpp</i>' :<br>
<table border="1" bgcolor="#FFFFFF">
<col>
<tbody>
<tr>
<td>
<pre><span class="pre">#include "../include/precompiled.h"
#include "../include/person.h"
#include "../include/global_validator.h"
#include &lt;QxOrm_Impl.h&gt;
</span>
QX_REGISTER_CPP_MY_EXE<span class="operator">(</span>person<span class="operator">)</span><span class="keyword">
namespace</span> qx<span class="operator"> {</span><span class="keyword">
template</span><span class="operator"> &lt;&gt;</span><span class="type"> void</span> register_class<span class="operator">(</span>QxClass<span class="operator">&lt;</span>person<span class="operator">&gt; &amp;</span> t<span class="operator">)
{</span>
t<span class="operator">.</span>id<span class="operator">(&amp;</span> person<span class="operator">::</span>_id<span class="operator">,</span><span class="string"> "id"</span><span class="operator">);</span>
t<span class="operator">.</span>data<span class="operator">(&amp;</span> person<span class="operator">::</span>_firstName<span class="operator">,</span><span class="string"> "firstName"</span><span class="operator">);</span>
t<span class="operator">.</span>data<span class="operator">(&amp;</span> person<span class="operator">::</span>_lastName<span class="operator">,</span><span class="string"> "lastName"</span><span class="operator">);</span>
t<span class="operator">.</span>data<span class="operator">(&amp;</span> person<span class="operator">::</span>_birthDate<span class="operator">,</span><span class="string"> "birthDate"</span><span class="operator">);</span>
t<span class="operator">.</span>data<span class="operator">(&amp;</span> person<span class="operator">::</span>_sex<span class="operator">,</span><span class="string"> "sex"</span><span class="operator">);</span>
QxValidatorX<span class="operator">&lt;</span>person<span class="operator">&gt; *</span> pAllValidator<span class="operator"> =</span> t<span class="operator">.</span>getAllValidator<span class="operator">();</span>
pAllValidator<span class="operator">-&gt;</span>add_NotEmpty<span class="operator">(</span><span class="string">"firstName"</span><span class="operator">);</span>
pAllValidator<span class="operator">-&gt;</span>add_NotEmpty<span class="operator">(</span><span class="string">"lastName"</span><span class="operator">,</span><span class="string"> "a person must have a lastname"</span><span class="operator">);</span>
pAllValidator<span class="operator">-&gt;</span>add_CustomValidator<span class="operator">(&amp;</span> person<span class="operator">::</span>isValid<span class="operator">);</span>
pAllValidator<span class="operator">-&gt;</span>add_CustomValidator_QVariant<span class="operator">(&amp;</span> validateFirstName<span class="operator">,</span><span class="string"> "firstName"</span><span class="operator">);</span>
pAllValidator<span class="operator">-&gt;</span>add_CustomValidator_DataType<span class="operator">&lt;</span>QDateTime<span class="operator">&gt;(&amp;</span> validateDateTime<span class="operator">,</span><span class="string"> "birthDate"</span><span class="operator">);
}}</span><span class="type">
void</span> person<span class="operator">::</span>isValid<span class="operator">(</span>qx<span class="operator">::</span>QxInvalidValueX<span class="operator"> &amp;</span> invalidValues<span class="operator">)
{</span><span class="comment">
// Cette m<>thode est appel<65>e automatiquement par le module 'QxValidator' :
// - avant d'ins<6E>rer ou mettre <20> jour une instance de type 'person' par les fonctions du namespace 'qx::dao' ;
// - en utilisant la fonction 'qx::validate()' avec pour param<61>tre une instance de type 'person'.
// L'enregistrement de la m<>thode 'person::isValid()' est effectu<74> dans la fonction de mapping :
// pAllValidator-&gt;add_CustomValidator(&amp; person::isValid);
// Dans cette m<>thode, il est possible de v<>rifier n'importe quelle valeur de l'instance courante
// Si une propri<72>t<EFBFBD> est non valide, il suffit d'ins<6E>rer un <20>l<EFBFBD>ment dans la collection 'invalidValues'
// Remarque : cette m<>thode est d<>clar<61>e 'private' pour forcer l'utilisateur <20> utiliser la fonction 'qx::validate()'
// Mais ce n'est pas une obligation : cette m<>thode peut <20>tre d<>clar<61>e 'public' ou 'protected'
// Par exemple, si on souhaite v<>rifier la propri<72>t<EFBFBD> '_sex' d'une personne :
</span><span class="flow"> if</span><span class="operator"> ((</span>_sex<span class="operator"> !=</span> male<span class="operator">) &amp;&amp; (</span>_sex<span class="operator"> !=</span> female<span class="operator">))
{</span> invalidValues<span class="operator">.</span>insert<span class="operator">(</span><span class="string">"le sexe de la personne doit <20>tre d<>fini : masculin ou f<>minin"</span><span class="operator">); }
}</span></pre>
</td>
</tr>
</tbody>
</table>
<br>
* fichier '<i>global_validator.h</i>' :<br>
<table border="1" bgcolor="#FFFFFF">
<col>
<tbody>
<tr>
<td>
<pre><span class="comment">// Les fonctions suivantes ('validateFirstName()' et 'validateDateTime()') sont globales (non li<6C>es <20> une classe)
// Elles peuvent ainsi <20>tre utilis<69>es par plusieurs classes pour valider une propri<72>t<EFBFBD> (par exemple : valider la saisie d'une adresse IP).
// Ces fonctions seront appel<65>es automatiquement par le module 'QxValidator' :
// - avant d'ins<6E>rer ou mettre <20> jour une instance de classe par les fonctions du namespace 'qx::dao' ;
// - en utilisant la fonction 'qx::validate()'.
</span><span class="type">
void</span> validateFirstName<span class="operator">(</span><span class="keyword">const</span> QVariant<span class="operator"> &amp;</span> value<span class="operator">,</span><span class="keyword"> const</span> qx<span class="operator">::</span>IxValidator<span class="operator"> *</span> validator<span class="operator">,</span> qx<span class="operator">::</span>QxInvalidValueX<span class="operator"> &amp;</span> invalidValues<span class="operator">)
{</span><span class="comment">
// Ici, on peut tester la valeur d'une propri<72>t<EFBFBD> (convertie en type QVariant)
// Si la valeur est invalide, il suffit d'ins<6E>rer un message <20> la collection 'invalidValues'
// Par exemple, si la valeur ne doit jamais <20>tre <20>gale <20> "admin" :
</span><span class="flow"> if</span><span class="operator"> (</span>value<span class="operator">.</span>toString<span class="operator">() ==</span><span class="string"> "admin"</span><span class="operator">)
{</span> invalidValues<span class="operator">.</span>insert<span class="operator">(</span><span class="string">"la valeur ne peut pas <20>tre <20>gale <20> 'admin'"</span><span class="operator">); }
}</span><span class="type">
void</span> validateDateTime<span class="operator">(</span><span class="keyword">const</span> QDateTime<span class="operator"> &amp;</span> value<span class="operator">,</span><span class="keyword"> const</span> qx<span class="operator">::</span>IxValidator<span class="operator"> *</span> validator<span class="operator">,</span> qx<span class="operator">::</span>QxInvalidValueX<span class="operator"> &amp;</span> invalidValues<span class="operator">)
{</span><span class="comment">
// Ici, on peut tester la valeur d'une propri<72>t<EFBFBD> (en conservant son vrai type, ici il s'agit de tester une date-heure de type 'QDateTime')
// Si la valeur est invalide, il suffit d'ins<6E>rer un message <20> la collection 'invalidValues'
// Par exemple, si la date-heure doit forc<72>ment <20>tre renseign<67>e :
</span><span class="flow"> if</span><span class="operator"> (!</span> value<span class="operator">.</span>isValid<span class="operator">())
{</span> invalidValues<span class="operator">.</span>insert<span class="operator">(</span><span class="string">"la date-heure doit <20>tre renseign<67>e et doit <20>tre valide"</span><span class="operator">); }
}</span></pre>
</td>
</tr>
</tbody>
</table>
<br>
* fichier '<i>main.cpp</i>' :<br>
<table border="1" bgcolor="#FFFFFF">
<col>
<tbody>
<tr>
<td>
<pre>person personValidate<span class="operator">;</span>
personValidate<span class="operator">.</span>_lastName<span class="operator"> =</span><span class="string"> "admin"</span><span class="operator">;</span>
qx<span class="operator">::</span>QxInvalidValueX invalidValues<span class="operator"> =</span> qx<span class="operator">::</span>validate<span class="operator">(</span>personValidate<span class="operator">);</span>
QString sInvalidValues<span class="operator"> =</span> invalidValues<span class="operator">.</span>text<span class="operator">();</span>
qDebug<span class="operator">(</span><span class="string">"[QxOrm] test 'QxValidator' module :\n%s"</span><span class="operator">,</span> qPrintable<span class="operator">(</span>sInvalidValues<span class="operator">));</span></pre>
</td>
</tr>
</tbody>
</table>
<br>
A l'ex<65>cution de ce bout de code, l'instance '<i>personValidate</i>' est non valide : la collection
'<i>invalidValues</i>' contient quatre <20>l<EFBFBD>ments :<br>
- "<i>la valeur de la propri<72>t<EFBFBD> 'firstName' ne peut pas <20>tre vide</i>" ;<br>
- "<i>le sexe de la personne doit <20>tre d<>fini : masculin ou f<>minin</i>" ;<br>
- "<i>la valeur ne peut pas <20>tre <20>gale <20> 'admin'</i>" ;<br>
- "<i>la date-heure doit <20>tre renseign<67>e et doit <20>tre valide</i>".<br>
<br>
Le module <b>QxValidator</b> fournit plusieurs validateurs pour effectuer des v<>rifications basiques :
<ul>
<li><i>add_NotNull()</i> : v<>rifie que la valeur n'est pas nulle ;</li>
<li><i>add_NotEmpty()</i> : v<>rifie que la cha<68>ne de caract<63>res n'est pas vide ;</li>
<li><i>add_MinValue()</i> : v<>rifie que la valeur num<75>rique n'est pas inf<6E>rieure au param<61>tre ;</li>
<li><i>add_MaxValue()</i> : v<>rifie que la valeur num<75>rique n'est pas sup<75>rieure au param<61>tre ;</li>
<li><i>add_Range()</i> : v<>rifie que la valeur num<75>rique est comprise entre les deux param<61>tres ;
</li>
<li><i>add_MinDecimal()</i> : v<>rifie que la valeur d<>cimale n'est pas inf<6E>rieure au param<61>tre ;
</li>
<li><i>add_MaxDecimal()</i> : v<>rifie que la valeur d<>cimale n'est pas sup<75>rieure au param<61>tre ;
</li>
<li><i>add_RangeDecimal()</i> : v<>rifie que la valeur d<>cimale est comprise entre les deux
param<61>tres ;</li>
<li><i>add_MinLength()</i> : v<>rifie que la cha<68>ne de caract<63>res a une taille minimale ;</li>
<li><i>add_MaxLength()</i> : v<>rifie que la cha<68>ne de caract<63>res ne d<>passe pas un certain nombre de
caract<63>res ;</li>
<li><i>add_Size()</i> : v<>rifie que la taille de la cha<68>ne de caract<63>res est comprise entre les deux
param<61>tres ;</li>
<li><i>add_DatePast()</i> : v<>rifie que la date-heure est dans le pass<73> ;</li>
<li><i>add_DateFuture()</i> : v<>rifie que la date-heure est dans le futur ;</li>
<li><i>add_RegExp()</i> : v<>rifie que la cha<68>ne de caract<63>res est compatible avec l'expression
r<>guli<6C>re pass<73>e en param<61>tre ;</li>
<li><i>add_EMail()</i> : v<>rifie que la cha<68>ne de caract<63>res correspond <20> un e-mail.</li>
</ul>
Comme dans l'exemple de la classe '<i>person</i>', il est possible de d<>finir <20>galement des
validateurs personnalis<69>s : ce sont des fonctions ou m<>thodes de classe qui seront appel<65>es
automatiquement par le module <b>QxValidator</b> pour valider une propri<72>t<EFBFBD> ou une instance de
classe.<br>
Il existe trois types de validateurs personnalis<69>s :
<ul>
<li><i>add_CustomValidator()</i> : m<>thode de classe, la signature de la m<>thode doit <20>tre "<i>void
my_class::my_method(qx::QxInvalidValueX &)</i>" ;</li>
<li><i>add_CustomValidator_QVariant()</i> : fonction globale avec type <i>QVariant</i> (propri<72>t<EFBFBD>
convertie en <i>QVariant</i>), la signature de la fonction doit <20>tre "<i>void my_validator(const
QVariant &, const qx::IxValidator *, qx::QxInvalidValueX &)</i>" ;</li>
<li><i>add_CustomValidator_DataType()</i> : fonction globale avec le type r<>el de la propri<72>t<EFBFBD>, la
signature de la fonction doit <20>tre "<i>void my_validator(const T &, const qx::IxValidator *,
qx::QxInvalidValueX &)</i>" ;</li>
</ul>
<b>Remarque :</b> <20> chaque validateur peut <20>tre associ<63> un groupe (param<61>tre optionnel pour chaque
m<>thode <i>add_XXX()</i> de la classe <i>qx::IxValidatorX</i>).<br>
Il est ainsi possible de cr<63>er des groupes de validation suivant le contexte d'ex<65>cution : par
exemple, valider la saisie d'une personne sur une IHM A ne n<>cessite peut-<2D>tre pas les m<>mes
v<>rifications que valider une personne sur une IHM B.<br>
Pour ex<65>cuter la validation d'une instance pour un groupe donn<6E> (par exemple "<i>myGroup</i>"), il
faut appeler la fonction suivante : "<i>qx::QxInvalidValueX invalidValues =
qx::validate(personValidate, "myGroup");</i>".<br>
<br>
<b>Autre remarque :</b> le module <b>QxValidator</b> d<>finit des messages par d<>faut lorsqu'une
contrainte n'est pas v<>rifi<66>e.<br>
Il est possible de red<65>finir ces messages par d<>faut en modifiant la collection suivante : "<i>QHash
<QString, QString> * lstMessage = QxClassX::getAllValidatorMessage();
</i>".<br>
Par exemple : "<i>lstMessage->insert("min_value", "la valeur '%NAME%' doit <20>tre inf<6E>rieure ou <20>gale <20>
'%CONSTRAINT%'");</i>".<br>
Les champs <i>%NAME%</i> et <i>%CONSTRAINT%</i> seront automatiquement remplac<61>s par les valeurs
correspondantes.<br>
Pour modifier le message pour un validateur donn<6E> (et non de mani<6E>re globale), il faut utiliser le
param<61>tre optionnel disponible pour les m<>thodes <i>add_XXX()</i> de la classe
<i>qx::IxValidatorX</i>.<br>
</td>
</tr>
</tbody>
</table>
<br><br>
<a name="faq_260"><u><b>Comment utiliser l'interface <i>qx::IxPersistable</i> ?</b></u></a><br><br>
<table border="0" style="width: 100%" align="center">
<col>
<col>
<tbody>
<tr>
<td valign="middle" width="30"></td>
<td align="justify">
L'interface <i><a href="../doxygen/html/classqx_1_1_ix_persistable.html"
target="_blank">qx::IxPersistable</a></i> (ou classe abstraite) dispose uniquement de m<>thodes
virtuelles pures.<br>
Elle permet d'avoir une classe de base commune pour appeler les fonctions de persistance sans
conna<6E>tre le type r<>el de l'instance courante (notion de polymorphisme).<br>
La biblioth<74>que QxOrm n'impose pas de travailler avec une classe de base pour enregistrer un type
persistant dans le contexte QxOrm, cependant il est parfois utile de disposer d'une interface afin
d'<27>crire des algorithmes g<>n<EFBFBD>riques.<br>
<br>
La classe <i>qx::IxPersistable</i> met <20> disposition les m<>thodes virtuelles suivantes (pour plus
d'informations sur ces m<>thodes, rendez-vous sur la <a href="../doxygen/index.html"
target="_blank">documentation en ligne de la biblioth<74>que QxOrm</a>) :<br>
<br>
<div style="width:900px; height:290px; overflow:auto; background-color:white">
<pre><span class="keyword">virtual</span><span class="type"> long</span> qxCount<span class="operator">(</span><span class="keyword">const</span> qx<span class="operator">::</span>QxSqlQuery<span class="operator"> &amp;</span> query<span class="operator"> =</span> qx<span class="operator">::</span>QxSqlQuery<span class="operator">(),</span> QSqlDatabase<span class="operator"> *</span> pDatabase<span class="operator"> =</span> NULL<span class="operator">);</span><span class="keyword">
virtual</span> QSqlError qxFetchById<span class="operator">(</span><span class="keyword">const</span> QVariant<span class="operator"> &amp;</span> id<span class="operator"> =</span> QVariant<span class="operator">(),</span><span class="keyword"> const</span> QStringList<span class="operator"> &amp;</span> columns<span class="operator"> =</span> QStringList<span class="operator">(),</span><span class="keyword"> const</span> QStringList<span class="operator"> &amp;</span> relation<span class="operator"> =</span> QStringList<span class="operator">(),</span> QSqlDatabase<span class="operator"> *</span> pDatabase<span class="operator"> =</span> NULL<span class="operator">);</span><span class="keyword">
virtual</span> QSqlError qxFetchAll<span class="operator">(</span>qx<span class="operator">::</span>IxCollection<span class="operator"> &amp;</span> list<span class="operator">,</span><span class="keyword"> const</span> QStringList<span class="operator"> &amp;</span> columns<span class="operator"> =</span> QStringList<span class="operator">(),</span><span class="keyword"> const</span> QStringList<span class="operator"> &amp;</span> relation<span class="operator"> =</span> QStringList<span class="operator">(),</span> QSqlDatabase<span class="operator"> *</span> pDatabase<span class="operator"> =</span> NULL<span class="operator">);</span><span class="keyword">
virtual</span> QSqlError qxFetchByQuery<span class="operator">(</span><span class="keyword">const</span> qx<span class="operator">::</span>QxSqlQuery<span class="operator"> &amp;</span> query<span class="operator">,</span> qx<span class="operator">::</span>IxCollection<span class="operator"> &amp;</span> list<span class="operator">,</span><span class="keyword"> const</span> QStringList<span class="operator"> &amp;</span> columns<span class="operator"> =</span> QStringList<span class="operator">(),</span><span class="keyword"> const</span> QStringList<span class="operator"> &amp;</span> relation<span class="operator"> =</span> QStringList<span class="operator">(),</span> QSqlDatabase<span class="operator"> *</span> pDatabase<span class="operator"> =</span> NULL<span class="operator">);</span><span class="keyword">
virtual</span> QSqlError qxInsert<span class="operator">(</span><span class="keyword">const</span> QStringList<span class="operator"> &amp;</span> relation<span class="operator"> =</span> QStringList<span class="operator">(),</span> QSqlDatabase<span class="operator"> *</span> pDatabase<span class="operator"> =</span> NULL<span class="operator">);</span><span class="keyword">
virtual</span> QSqlError qxUpdate<span class="operator">(</span><span class="keyword">const</span> qx<span class="operator">::</span>QxSqlQuery<span class="operator"> &amp;</span> query<span class="operator"> =</span> qx<span class="operator">::</span>QxSqlQuery<span class="operator">(),</span><span class="keyword"> const</span> QStringList<span class="operator"> &amp;</span> columns<span class="operator"> =</span> QStringList<span class="operator">(),</span><span class="keyword"> const</span> QStringList<span class="operator"> &amp;</span> relation<span class="operator"> =</span> QStringList<span class="operator">(),</span> QSqlDatabase<span class="operator"> *</span> pDatabase<span class="operator"> =</span> NULL<span class="operator">);</span><span class="keyword">
virtual</span> QSqlError qxSave<span class="operator">(</span><span class="keyword">const</span> QStringList<span class="operator"> &amp;</span> relation<span class="operator"> =</span> QStringList<span class="operator">(),</span> QSqlDatabase<span class="operator"> *</span> pDatabase<span class="operator"> =</span> NULL<span class="operator">);</span><span class="keyword">
virtual</span> QSqlError qxDeleteById<span class="operator">(</span><span class="keyword">const</span> QVariant<span class="operator"> &amp;</span> id<span class="operator"> =</span> QVariant<span class="operator">(),</span> QSqlDatabase<span class="operator"> *</span> pDatabase<span class="operator"> =</span> NULL<span class="operator">);</span><span class="keyword">
virtual</span> QSqlError qxDeleteAll<span class="operator">(</span>QSqlDatabase<span class="operator"> *</span> pDatabase<span class="operator"> =</span> NULL<span class="operator">);</span><span class="keyword">
virtual</span> QSqlError qxDeleteByQuery<span class="operator">(</span><span class="keyword">const</span> qx<span class="operator">::</span>QxSqlQuery<span class="operator"> &amp;</span> query<span class="operator">,</span> QSqlDatabase<span class="operator"> *</span> pDatabase<span class="operator"> =</span> NULL<span class="operator">);</span><span class="keyword">
virtual</span> QSqlError qxDestroyById<span class="operator">(</span><span class="keyword">const</span> QVariant<span class="operator"> &amp;</span> id<span class="operator"> =</span> QVariant<span class="operator">(),</span> QSqlDatabase<span class="operator"> *</span> pDatabase<span class="operator"> =</span> NULL<span class="operator">);</span><span class="keyword">
virtual</span> QSqlError qxDestroyAll<span class="operator">(</span>QSqlDatabase<span class="operator"> *</span> pDatabase<span class="operator"> =</span> NULL<span class="operator">);</span><span class="keyword">
virtual</span> QSqlError qxDestroyByQuery<span class="operator">(</span><span class="keyword">const</span> qx<span class="operator">::</span>QxSqlQuery<span class="operator"> &amp;</span> query<span class="operator">,</span> QSqlDatabase<span class="operator"> *</span> pDatabase<span class="operator"> =</span> NULL<span class="operator">);</span><span class="keyword">
virtual</span> qx_bool qxExist<span class="operator">(</span><span class="keyword">const</span> QVariant<span class="operator"> &amp;</span> id<span class="operator"> =</span> QVariant<span class="operator">(),</span> QSqlDatabase<span class="operator"> *</span> pDatabase<span class="operator"> =</span> NULL<span class="operator">);</span><span class="keyword">
virtual</span> qx<span class="operator">::</span>QxInvalidValueX qxValidate<span class="operator">(</span><span class="keyword">const</span> QStringList<span class="operator"> &amp;</span> groups<span class="operator"> =</span> QStringList<span class="operator">());</span><span class="keyword">
virtual</span> qx<span class="operator">::</span>IxPersistableCollection_ptr qxNewPersistableCollection<span class="operator">()</span><span class="keyword"> const</span><span class="operator">;</span><span class="keyword">
virtual</span> qx<span class="operator">::</span>IxClass<span class="operator"> *</span> qxClass<span class="operator">()</span><span class="keyword"> const</span><span class="operator">;</span></pre>
</div>
<br>
Par exemple, <20> partir d'une liste de pointeurs de type <i>qx::IxPersistable</i>, il est possible
d'enregistrer les <20>l<EFBFBD>ments dans plusieurs tables diff<66>rentes de la base de donn<6E>es de la fa<66>on
suivante :<br>
<br>
<table border="1" bgcolor="#FFFFFF">
<col>
<tbody>
<tr>
<td>
<pre>QList<span class="operator">&lt;</span>qx<span class="operator">::</span>IxPersistable<span class="operator"> *&gt;</span> lst<span class="operator"> = ...;</span>
foreach<span class="operator">(</span>qx<span class="operator">::</span>IxPersistable<span class="operator"> *</span> p<span class="operator">,</span> lst<span class="operator">)
{</span>
QSqlError daoError<span class="operator"> =</span> p<span class="operator">-&gt;</span>qxSave<span class="operator">();</span><span class="flow">
if</span><span class="operator"> (</span>daoError<span class="operator">.</span>isValid<span class="operator">()) {</span><span class="comment"> /* an error occured */</span><span class="operator"> }</span><span class="comment">
// etc...
</span><span class="operator">}</span></pre>
</td>
</tr>
</tbody>
</table>
<br>
Pour impl<70>menter l'interface <i>qx::IxPersistable</i>, il faut :
<ul>
<li>faire h<>riter la classe persistante du type <i>qx::IxPersistable</i> ;</li>
<li>dans la d<>finition de la classe (<i>myClass.h</i> par exemple), ajouter la macro
<i>QX_PERSISTABLE_HPP(myClass)</i> ;
</li>
<li>dans l'impl<70>mentation de la classe (<i>myClass.cpp</i> par exemple), ajouter la macro
<i>QX_PERSISTABLE_CPP(myClass)</i>.
</li>
</ul>
Par exemple, impl<70>menter l'interface <i>qx::IxPersistable</i> pour la classe <a
href="./tutorial.html#tuto_6"><i>author</i></a> du tutoriel <i>qxBlog</i> revient <20> <20>crire (les
modifications par rapport au code du tutoriel apparaissent en gras) :<br>
<br>
<table border="1" bgcolor="#FFFFFF">
<col>
<tbody>
<tr>
<td title="author.h">
<pre><span class="pre">#ifndef _QX_BLOG_AUTHOR_H_
#define _QX_BLOG_AUTHOR_H_
</span><span class="keyword">
class</span> blog<span class="operator">;</span><span class="keyword">
class</span> QX_BLOG_DLL_EXPORT author : <font style="background-color:yellow"><b>public qx::IxPersistable</b></font><span class="operator">
{</span>
<font style="background-color:yellow"><b>QX_PERSISTABLE_HPP(author)</b></font>
<span class="keyword">public</span><span class="operator">:</span><span class="comment">
// -- typedef
</span><span class="keyword"> typedef</span> boost<span class="operator">::</span>shared_ptr<span class="operator">&lt;</span>blog<span class="operator">&gt;</span> blog_ptr<span class="operator">;</span><span class="keyword">
typedef</span> std<span class="operator">::</span>vector<span class="operator">&lt;</span>blog_ptr<span class="operator">&gt;</span> list_blog<span class="operator">;</span><span class="comment">
// -- enum
</span><span class="keyword"> enum</span> enum_sex<span class="operator"> {</span> male<span class="operator">,</span> female<span class="operator">,</span> unknown<span class="operator"> };</span><span class="comment">
// -- propri<72>t<EFBFBD>s
</span> QString m_id<span class="operator">;</span>
QString m_name<span class="operator">;</span>
QDate m_birthdate<span class="operator">;</span>
enum_sex m_sex<span class="operator">;</span>
list_blog m_blogX<span class="operator">;</span><span class="comment">
// -- constructeur, destructeur virtuel
</span> author<span class="operator">() :</span> m_id<span class="operator">(</span><span class="int">0</span><span class="operator">),</span> m_sex<span class="operator">(</span>unknown<span class="operator">) { ; }</span><span class="keyword">
virtual</span><span class="operator"> ~</span>author<span class="operator">() { ; }</span><span class="comment">
// -- m<>thodes
</span><span class="type"> int</span> age<span class="operator">()</span><span class="keyword"> const</span><span class="operator">;
};</span>
QX_REGISTER_PRIMARY_KEY<span class="operator">(</span>author<span class="operator">,</span> QString<span class="operator">)</span>
QX_REGISTER_HPP_QX_BLOG<span class="operator">(</span>author<span class="operator">,</span> qx<span class="operator">::</span>trait<span class="operator">::</span>no_base_class_defined<span class="operator">,</span><span class="int"> 0</span><span class="operator">)</span><span class="keyword">
typedef</span> boost<span class="operator">::</span>shared_ptr<span class="operator">&lt;</span>author<span class="operator">&gt;</span> author_ptr<span class="operator">;</span><span class="keyword">
typedef</span> qx<span class="operator">::</span>QxCollection<span class="operator">&lt;</span>QString<span class="operator">,</span> author_ptr<span class="operator">&gt;</span> list_author<span class="operator">;</span><span class="pre">
#endif <span class="comment">// _QX_BLOG_AUTHOR_H_</span>
</span></pre>
</td>
</tr>
</tbody>
</table>
<br>
<table border="1" bgcolor="#FFFFFF">
<col>
<tbody>
<tr>
<td title="author.cpp">
<pre><span class="pre">#include <span class="string">"../include/precompiled.h"</span>
#include <span class="string">"../include/author.h"</span>
#include <span class="string">"../include/blog.h"</span>
#include <span class="string">&lt;QxOrm_Impl.h&gt;</span>
</span>
QX_REGISTER_CPP_QX_BLOG<span class="operator">(</span>author<span class="operator">)</span>
<font style="background-color:yellow"><b>QX_PERSISTABLE_CPP(author)</b></font>
<span class="keyword">namespace</span> qx<span class="operator"> {</span><span class="keyword">
template</span><span class="operator"> &lt;&gt;</span><span class="type"> void</span> register_class<span class="operator">(</span>QxClass<span class="operator">&lt;</span>author<span class="operator">&gt; &amp;</span> t<span class="operator">)
{</span>
t<span class="operator">.</span>id<span class="operator">(&amp;</span> author<span class="operator">::</span>m_id<span class="operator">,</span><span class="string"> "author_id"</span><span class="operator">);</span>
t<span class="operator">.</span>data<span class="operator">(&amp;</span> author<span class="operator">::</span>m_name<span class="operator">,</span><span class="string"> "name"</span><span class="operator">);</span>
t<span class="operator">.</span>data<span class="operator">(&amp;</span> author<span class="operator">::</span>m_birthdate<span class="operator">,</span><span class="string"> "birthdate"</span><span class="operator">);</span>
t<span class="operator">.</span>data<span class="operator">(&amp;</span> author<span class="operator">::</span>m_sex<span class="operator">,</span><span class="string"> "sex"</span><span class="operator">);</span>
t<span class="operator">.</span>relationOneToMany<span class="operator">(&amp;</span> author<span class="operator">::</span>m_blogX<span class="operator">,</span><span class="string"> "list_blog"</span><span class="operator">,</span><span class="string"> "author_id"</span><span class="operator">);</span>
t<span class="operator">.</span>fct_0<span class="operator">&lt;</span><span class="type">int</span><span class="operator">&gt;(&amp;</span> author<span class="operator">::</span>age<span class="operator">,</span><span class="string"> "age"</span><span class="operator">);
}}</span><span class="type">
int</span> author<span class="operator">::</span>age<span class="operator">()</span><span class="keyword"> const</span><span class="operator">
{</span><span class="flow">
if</span><span class="operator"> (!</span> m_birthdate<span class="operator">.</span>isValid<span class="operator">()) {</span><span class="flow"> return</span><span class="operator"> -</span><span class="int">1</span><span class="operator">; }</span><span class="flow">
return</span><span class="operator"> (</span>QDate<span class="operator">::</span>currentDate<span class="operator">().</span>year<span class="operator">() -</span> m_birthdate<span class="operator">.</span>year<span class="operator">());
}</span>
</pre>
</td>
</tr>
</tbody>
</table>
<br>
<b>Remarque :</b> le projet de test <i>./test/qxDllSample/dll1/</i> met <20> disposition une sorte de
'super classe de base' : la classe <i>qx::QxPersistable</i> impl<70>mente l'interface <i><a
href="../doxygen/html/classqx_1_1_ix_persistable.html" target="_blank">qx::IxPersistable</a></i>
et h<>rite de <i>QObject</i>.<br>
Le m<>canisme <i>SIGNAL-SLOT</i> de Qt peut donc <20>tre utilis<69> avec cette classe, ce qui peut <20>tre
int<6E>ressant par exemple pour la notion de d<>clencheurs (ou <a
href="./faq.html#faq_130"><i>trigger</i></a>).<br>
La classe <i>qx::QxPersistable</i> met <20>galement <20> disposition des m<>thodes virtuelles qu'il est
possible de surcharger pour g<>rer notamment la notion de validation des donn<6E>es avec le module <a
href="./faq.html#faq_250"><i>QxValidator</i></a>.<br>
La classe <i>qx::QxPersistable</i> ne fait pas partie de la distribution de QxOrm, mais il est
possible de la copier-coller dans un projet afin de profiter de ses fonctionnalit<69>s :
<ul>
<li>acc<EFBFBD>der au fichier <a href="./resource/qx_persistable_hpp.html"
target="_blank"><i>QxPersistable.hpp</i></a> ;</li>
<li>acc<EFBFBD>der au fichier <a href="./resource/qx_persistable_cpp.html"
target="_blank"><i>QxPersistable.cpp</i></a>.</li>
</ul>
</td>
</tr>
</tbody>
</table>
<br><br>
<a name="faq_270"><u><b>Comment utiliser le moteur de relations pour r<>cup<75>rer des donn<6E>es associ<63>es <20>
plusieurs tables ?</b></u></a><br><br>
<table border="0" style="width: 100%" align="center">
<col>
<col>
<tbody>
<tr>
<td valign="middle" width="30"></td>
<td align="justify">
La biblioth<74>que QxOrm supporte quatre types de relations pour lier les classes C++ enregistr<74>es dans
le contexte QxOrm : <i>one-to-one</i>, <i>one-to-many</i>, <i>many-to-one</i> et
<i>many-to-many</i>.<br>
Pour plus de d<>tails sur la d<>finition de ces relations, il est conseill<6C> de lire <a
href="./tutorial.html" target="_blank">le tutoriel qxBlog</a>.<br>
Nous allons d<>tailler dans cette Q&R les diff<66>rentes m<>thodes de r<>cup<75>ration des donn<6E>es (module <a
href="../doxygen/html/group___qx_dao.html" target="_blank">QxDao</a>, fonctions du namespace <a
href="../doxygen/html/namespaceqx_1_1dao.html" target="_blank">qx::dao</a>) :
<ul>
<li><a href="../doxygen/html/namespaceqx_1_1dao.html" target="_blank">fetch_by_id</a>, <a
href="../doxygen/html/namespaceqx_1_1dao.html" target="_blank">fetch_all</a> et <a
href="../doxygen/html/namespaceqx_1_1dao.html" target="_blank">fetch_by_query</a> : r<>cup<75>re les
donn<6E>es en requ<71>tant une seule table de la base de donn<6E>es (on parle alors de mode <i>lazy
fetch</i>) ;</li>
<li><a href="../doxygen/html/namespaceqx_1_1dao.html"
target="_blank">fetch_by_id_with_all_relation</a>, <a
href="../doxygen/html/namespaceqx_1_1dao.html" target="_blank">fetch_all_with_all_relation</a>
et <a href="../doxygen/html/namespaceqx_1_1dao.html"
target="_blank">fetch_by_query_with_all_relation</a> : r<>cup<75>re les donn<6E>es en requ<71>tant une
table + toutes ses tables li<6C>es (soit une requ<71>te sur plusieurs tables de la base de donn<6E>es, on
parle alors de mode <i>eager fetch</i>) ;</li>
<li><a href="../doxygen/html/namespaceqx_1_1dao.html" target="_blank">fetch_by_id_with_relation</a>,
<a href="../doxygen/html/namespaceqx_1_1dao.html" target="_blank">fetch_all_with_relation</a> et
<a href="../doxygen/html/namespaceqx_1_1dao.html" target="_blank">fetch_by_query_with_relation</a>
: <20>quivalent aux fonctions ci-dessus (mode <i>eager fetch</i>) avec possibilit<69> de pr<70>ciser les
relations <20> r<>cup<75>rer sur plusieurs niveaux.
</li>
</ul>
Le premier param<61>tre des fonctions <a href="../doxygen/html/namespaceqx_1_1dao.html"
target="_blank">fetch_by_id_with_relation</a>, <a href="../doxygen/html/namespaceqx_1_1dao.html"
target="_blank">fetch_all_with_relation</a> et <a href="../doxygen/html/namespaceqx_1_1dao.html"
target="_blank">fetch_by_query_with_relation</a> correspond <20> la liste des relations <20> requ<71>ter.<br>
Cette liste de relations peut contenir les <20>l<EFBFBD>ments suivants :
<ul>
<li>identifiant d'une relation : chaque relation poss<73>de une cl<63> d<>finie au niveau de la fonction de
param<61>trage <i>qx::register_class&lt;T&gt;</i> ;</li>
<li>le mot-cl<63> "<i>*</i>" signifie "<i>r<EFBFBD>cup<EFBFBD>rer toutes les relations d<>finies dans la fonction de
param<61>trage <i>qx::register_class&lt;T&gt;</i> sur un niveau</i>" ;</li>
<li>le mot-cl<63> "<i>-></i>" signifie jointure de type "<i>LEFT OUTER JOIN</i>" (jointure par d<>faut
de la biblioth<74>que QxOrm) ;</li>
<li>le mot-cl<63> "<i>>></i>" signifie jointure de type "<i>INNER JOIN</i>" entre deux tables.</li>
</ul>
<b>Remarque :</b> en utilisant le mot-cl<63> "*" pour indiquer "<i>toutes les relations sur un
niveau</i>", les appels suivants sont <20>quivalents :
<ul>
<li><i>qx::dao::fetch_by_id_with_relation(<b>"*"</b>, ...)</i> ==
<i>qx::dao::fetch_by_id_with_all_relation(...)</i> ;
</li>
<li><i>qx::dao::fetch_by_query_with_relation(<b>"*"</b>, ...)</i> ==
<i>qx::dao::fetch_by_query_with_all_relation(...)</i> ;
</li>
<li><i>qx::dao::fetch_all_with_relation(<b>"*"</b>, ...)</i> ==
<i>qx::dao::fetch_all_with_all_relation(...)</i>.
</li>
</ul>
<br>
<b>Exemple :</b> <20> partir du tutoriel qxBlog, il est possible de r<>cup<75>rer les donn<6E>es suivantes avec
une seule requ<71>te :<br>
<br>
<b>1-</b> r<>cup<75>rer un <i>blog</i> et son <i>author</i> ;<br>
<b>2-</b> pour l'<i>author</i> valoris<69>, r<>cup<75>rer tous les <i>blog</i> qu'il a <20>crit ;<br>
<b>3-</b> pour chaque <i>blog</i> que l'<i>author</i> a <20>crit, r<>cup<75>rer tous les <i>comment</i>
associ<63>s.<br>
<br>
<table border="1" bgcolor="#FFFFFF">
<col>
<tbody>
<tr>
<td title="complex fetch with relationships">
<pre>blog_ptr my_blog<span class="operator"> =</span> blog_ptr<span class="operator">(</span><span class="keyword">new</span> blog<span class="operator">(</span><span class="int">10</span><span class="operator">));</span>
QSqlError daoError<span class="operator"> =</span> qx<span class="operator">::</span>dao<span class="operator">::</span>fetch_by_id_with_relation<span class="operator">(</span><span class="string">"author_id-&gt;list_blog-&gt;list_comment"</span><span class="operator">,</span> my_blog<span class="operator">);</span></pre>
</td>
</tr>
</tbody>
</table>
<br>
Ce qui g<>n<EFBFBD>re la requ<71>te SQL suivante :
<div style="width:900px; height:180px; overflow:auto; background-color:white">
<pre><span class="int">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,
blog_2.blog_id AS blog_2_blog_id_0, blog_2.author_id AS blog_2_author_id_0, blog_2.blog_text AS blog_2_blog_text_0, blog_2.date_creation AS blog_2_date_creation_0,
comment_4.comment_id AS comment_4_comment_id_0, comment_4.blog_id AS comment_4_blog_id_0, comment_4.comment_text AS comment_4_comment_text_0, comment_4.date_creation AS comment_4_date_creation_0
FROM blog
LEFT OUTER JOIN author author_1 ON author_1.author_id = blog.author_id
LEFT OUTER JOIN blog blog_2 ON blog_2.author_id = author_1.author_id
LEFT OUTER JOIN comment comment_4 ON comment_4.blog_id = blog_2.blog_id
WHERE blog.blog_id = :blog_id</span></pre>
</div>
<br><br>
<b>Autre exemple :</b> il est <20>galement possible de cr<63>er une liste de relations <20> r<>cup<75>rer, comme
ceci par exemple :<br>
<br>
<table border="1" bgcolor="#FFFFFF">
<col>
<tbody>
<tr>
<td title="complex fetch with relationships">
<pre>blog_ptr my_blog<span class="operator"> =</span> blog_ptr<span class="operator">(</span><span class="keyword">new</span> blog<span class="operator">(</span><span class="int">10</span><span class="operator">));</span>
QStringList relation<span class="operator">;</span>
relation<span class="operator"> &lt;&lt;</span><span class="string"> "author_id-&gt;list_blog-&gt;list_comment"</span><span class="operator">;</span>
relation<span class="operator"> &lt;&lt;</span><span class="string"> "author_id-&gt;list_blog-&gt;list_category"</span><span class="operator">;</span>
relation<span class="operator"> &lt;&lt;</span><span class="string"> "list_comment"</span><span class="operator">;</span>
relation<span class="operator"> &lt;&lt;</span><span class="string"> "list_category"</span><span class="operator">;</span>
QSqlError daoError<span class="operator"> =</span> qx<span class="operator">::</span>dao<span class="operator">::</span>fetch_by_id_with_relation<span class="operator">(</span>relation<span class="operator">,</span> my_blog<span class="operator">);</span></pre>
</td>
</tr>
</tbody>
</table>
<br>
Ce qui g<>n<EFBFBD>re la requ<71>te SQL suivante :
<div style="width:900px; height:270px; overflow:auto; background-color:white">
<pre><span class="int">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,
blog_2.blog_id AS blog_2_blog_id_0, blog_2.author_id AS blog_2_author_id_0, blog_2.blog_text AS blog_2_blog_text_0, blog_2.date_creation AS blog_2_date_creation_0,
category_5.category_id AS category_5_category_id_0, category_5.name AS category_5_name_0, category_5.description AS category_5_description_0,
comment_6.comment_id AS comment_6_comment_id_0, comment_6.blog_id AS comment_6_blog_id_0, comment_6.comment_text AS comment_6_comment_text_0, comment_6.date_creation AS comment_6_date_creation_0,
category_7.category_id AS category_7_category_id_0, category_7.name AS category_7_name_0, category_7.description AS category_7_description_0
FROM blog
LEFT OUTER JOIN author author_1 ON author_1.author_id = blog.author_id
LEFT OUTER JOIN blog blog_2 ON blog_2.author_id = author_1.author_id
LEFT OUTER JOIN category_blog category_blog_5 ON blog_2.blog_id = category_blog_5.blog_id
LEFT OUTER JOIN category category_5 ON category_blog_5.category_id = category_5.category_id
LEFT OUTER JOIN comment comment_6 ON comment_6.blog_id = blog.blog_id
LEFT OUTER JOIN category_blog category_blog_7 ON blog.blog_id = category_blog_7.blog_id
LEFT OUTER JOIN category category_7 ON category_blog_7.category_id = category_7.category_id
WHERE blog.blog_id = :blog_id</span></pre>
</div>
<br><br>
<b>Autre exemple :</b> pour r<>cup<75>rer toutes les relations pour un niveau donn<6E>, il faut utiliser le
mot-cl<63> "*".<br>
Pour r<>cup<75>rer toutes les donn<6E>es de toutes les relations sur trois niveaux, il faut <20>crire :<br>
<br>
<table border="1" bgcolor="#FFFFFF">
<col>
<tbody>
<tr>
<td title="complex fetch with relationships">
<pre>blog_ptr my_blog<span class="operator"> =</span> blog_ptr<span class="operator">(</span><span class="keyword">new</span> blog<span class="operator">(</span><span class="int">10</span><span class="operator">));</span>
QSqlError daoError<span class="operator"> =</span> qx<span class="operator">::</span>dao<span class="operator">::</span>fetch_by_id_with_relation<span class="operator">(</span><span class="string">"*-&gt;*-&gt;*"</span><span class="operator">,</span> my_blog<span class="operator">);</span></pre>
</td>
</tr>
</tbody>
</table>
<br>
Ce qui g<>n<EFBFBD>re la requ<71>te SQL suivante :
<div style="width:900px; height:620px; overflow:auto; background-color:white">
<pre><span class="int">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,
blog_2.blog_id AS blog_2_blog_id_0, blog_2.author_id AS blog_2_author_id_0, blog_2.blog_text AS blog_2_blog_text_0, blog_2.date_creation AS blog_2_date_creation_0, blog_2.author_id AS blog_2_author_id_0_2,
author_3.author_id AS author_3_author_id_0, author_3.name AS author_3_name_0, author_3.birthdate AS author_3_birthdate_0, author_3.sex AS author_3_sex_0,
comment_4.comment_id AS comment_4_comment_id_0, comment_4.blog_id AS comment_4_blog_id_0, comment_4.comment_text AS comment_4_comment_text_0, comment_4.date_creation AS comment_4_date_creation_0,
category_5.category_id AS category_5_category_id_0, category_5.name AS category_5_name_0, category_5.description AS category_5_description_0,
comment_6.comment_id AS comment_6_comment_id_0, comment_6.blog_id AS comment_6_blog_id_0, comment_6.comment_text AS comment_6_comment_text_0, comment_6.date_creation AS comment_6_date_creation_0, comment_6.blog_id AS comment_6_blog_id_0_6,
blog_7.blog_id AS blog_7_blog_id_0, blog_7.blog_text AS blog_7_blog_text_0, blog_7.date_creation AS blog_7_date_creation_0, blog_7.author_id AS blog_7_author_id_0_7,
author_8.author_id AS author_8_author_id_0, author_8.name AS author_8_name_0, author_8.birthdate AS author_8_birthdate_0, author_8.sex AS author_8_sex_0,
comment_9.comment_id AS comment_9_comment_id_0, comment_9.blog_id AS comment_9_blog_id_0, comment_9.comment_text AS comment_9_comment_text_0, comment_9.date_creation AS comment_9_date_creation_0,
category_10.category_id AS category_10_category_id_0, category_10.name AS category_10_name_0, category_10.description AS category_10_description_0,
category_11.category_id AS category_11_category_id_0, category_11.name AS category_11_name_0, category_11.description AS category_11_description_0,
blog_12.blog_id AS blog_12_blog_id_0, blog_12.blog_text AS blog_12_blog_text_0, blog_12.date_creation AS blog_12_date_creation_0, blog_12.author_id AS blog_12_author_id_0_12,
author_13.author_id AS author_13_author_id_0, author_13.name AS author_13_name_0, author_13.birthdate AS author_13_birthdate_0, author_13.sex AS author_13_sex_0,
comment_14.comment_id AS comment_14_comment_id_0, comment_14.blog_id AS comment_14_blog_id_0, comment_14.comment_text AS comment_14_comment_text_0, comment_14.date_creation AS comment_14_date_creation_0,
category_15.category_id AS category_15_category_id_0, category_15.name AS category_15_name_0, category_15.description AS category_15_description_0
FROM blog
LEFT OUTER JOIN author author_1 ON author_1.author_id = blog.author_id
LEFT OUTER JOIN blog blog_2 ON blog_2.author_id = author_1.author_id
LEFT OUTER JOIN author author_3 ON author_3.author_id = blog_2.author_id
LEFT OUTER JOIN comment comment_4 ON comment_4.blog_id = blog_2.blog_id
LEFT OUTER JOIN category_blog category_blog_5 ON blog_2.blog_id = category_blog_5.blog_id
LEFT OUTER JOIN category category_5 ON category_blog_5.category_id = category_5.category_id
LEFT OUTER JOIN comment comment_6 ON comment_6.blog_id = blog.blog_id
LEFT OUTER JOIN blog blog_7 ON blog_7.blog_id = comment_6.blog_id
LEFT OUTER JOIN author author_8 ON author_8.author_id = blog_7.author_id
LEFT OUTER JOIN comment comment_9 ON comment_9.blog_id = blog_7.blog_id
LEFT OUTER JOIN category_blog category_blog_10 ON blog_7.blog_id = category_blog_10.blog_id
LEFT OUTER JOIN category category_10 ON category_blog_10.category_id = category_10.category_id
LEFT OUTER JOIN category_blog category_blog_11 ON blog.blog_id = category_blog_11.blog_id
LEFT OUTER JOIN category category_11 ON category_blog_11.category_id = category_11.category_id
LEFT OUTER JOIN category_blog category_blog_12 ON category_11.category_id = category_blog_12.category_id
LEFT OUTER JOIN blog blog_12 ON category_blog_12.blog_id = blog_12.blog_id
LEFT OUTER JOIN author author_13 ON author_13.author_id = blog_12.author_id
LEFT OUTER JOIN comment comment_14 ON comment_14.blog_id = blog_12.blog_id
LEFT OUTER JOIN category_blog category_blog_15 ON blog_12.blog_id = category_blog_15.blog_id
LEFT OUTER JOIN category category_15 ON category_blog_15.category_id = category_15.category_id
WHERE blog.blog_id = :blog_id</span></pre>
</div>
<br>
</td>
</tr>
</tbody>
</table>
<br><br>
<a name="faq_280"><u><b>Comment appeler une proc<6F>dure stock<63>e ou une requ<71>te SQL personnalis<69>e
?</b></u></a><br><br>
<table border="0" style="width: 100%" align="center">
<col>
<col>
<tbody>
<tr>
<td valign="middle" width="30"></td>
<td align="justify">
La biblioth<74>que QxOrm fournit deux fonctions pour appeler une proc<6F>dure stock<63>e ou une requ<71>te SQL
personnalis<69>e :
<ul>
<li><a href="../doxygen/html/namespaceqx_1_1dao.html"
target="_blank">qx::dao::execute_query&lt;T&gt;()</a></li>
<li><a href="../doxygen/html/namespaceqx_1_1dao.html" target="_blank">qx::dao::call_query()</a></li>
</ul>
Le premier param<61>tre de ces deux fonctions, de type <i><a
href="../doxygen/html/classqx_1_1_qx_sql_query.html" target="_blank">qx::QxSqlQuery</a></i> (ou
<i>qx_query</i>), correspond <20> la proc<6F>dure stock<63>e ou <20> la requ<71>te SQL personnalis<69>e.<br>
Pour plus d'informations sur la classe <i><a href="../doxygen/html/classqx_1_1_qx_sql_query.html"
target="_blank">qx::QxSqlQuery</a></i>, rendez-vous sur cette Q&R de la FAQ de QxOrm : <a
href="./faq.html#faq_210">Comment construire une requ<71>te pour interroger la base de donn<6E>es sans
<20>crire de SQL avec la classe <i>qx::QxSqlQuery</i> ?</a><br>
<br>
La fonction <a href="../doxygen/html/namespaceqx_1_1dao.html"
target="_blank">qx::dao::execute_query&lt;T&gt;()</a> est une fonction <i>template</i> : le type T
doit <20>tre enregistr<74> dans le contexte QxOrm (fonction <i>qx::register_class&lt;T&gt;</i>).<br>
Toutes les donn<6E>es renvoy<6F>es par la proc<6F>dure stock<63>e ou la requ<71>te SQL personnalis<69>e qui pourront
<20>tre associ<63>es aux membres des classes C++ (de type T) seront valoris<69>es automatiquement.<br>
Une recherche automatique est effectu<74>e sur le nom des champs associ<63>s aux donn<6E>es.<br>
Voici un exemple d'utilisation (disponible dans le projet qxBlog du package QxOrm) :<br>
<br>
<table border="1" bgcolor="#FFFFFF">
<col>
<tbody>
<tr>
<td>
<pre><span class="comment">// Call a custom SQL query or a stored procedure and fetch automatically properties (with a collection of items)
</span>qx_query testStoredProcBis<span class="operator">(</span><span class="string">"SELECT * FROM author"</span><span class="operator">);</span>
daoError<span class="operator"> =</span> qx<span class="operator">::</span>dao<span class="operator">::</span>execute_query<span class="operator">(</span>testStoredProcBis<span class="operator">,</span> authorX<span class="operator">);</span>
qAssert<span class="operator">(!</span> daoError<span class="operator">.</span>isValid<span class="operator">());</span> qAssert<span class="operator">(</span>authorX<span class="operator">.</span>count<span class="operator">() &gt;</span><span class="int"> 0</span><span class="operator">);</span>
qx<span class="operator">::</span>dump<span class="operator">(</span>authorX<span class="operator">);</span></pre>
</td>
</tr>
</tbody>
</table>
<br><br>
La fonction <a href="../doxygen/html/namespaceqx_1_1dao.html"
target="_blank">qx::dao::call_query()</a> n'est pas une fonction <i>template</i> : les r<>sultats de
la requ<71>te doivent <20>tre parcourus manuellement sur la classe <i><a
href="../doxygen/html/classqx_1_1_qx_sql_query.html" target="_blank">qx::QxSqlQuery</a></i> (ou
<i>qx_query</i>).<br>
Pour r<>cup<75>rer un param<61>tre de sortie (qui doit <20>tre pass<73> <20> la requ<71>te en tant que <i>QSql::Out</i>
ou <i>QSql::InOut</i>), il suffit d'utiliser la m<>thode : <i>QVariant qx::QxSqlQuery::boundValue(const
QString & sKey) const;</i>.<br>
<br>
Pour parcourir la liste des r<>sultats de la requ<71>te, il faut utiliser les m<>thodes suivantes :<br>
* <i>long qx::QxSqlQuery::getSqlResultRowCount() const;</i><br>
* <i>long qx::QxSqlQuery::getSqlResultColumnCount() const;</i><br>
* <i>QVariant qx::QxSqlQuery::getSqlResultAt(long row, long column) const;</i><br>
* <i>QVariant qx::QxSqlQuery::getSqlResultAt(long row, const QString & column) const;</i><br>
* <i>QVector qx::QxSqlQuery::getSqlResultAllColumns() const;</i><br>
* <i>void qx::QxSqlQuery::dumpSqlResult();</i><br>
<br>
Voici un exemple d'utilisation avec la fonction <a href="../doxygen/html/namespaceqx_1_1dao.html"
target="_blank">qx::dao::call_query()</a> :<br>
<br>
<table border="1" bgcolor="#FFFFFF">
<col>
<tbody>
<tr>
<td>
<pre>qx_query query<span class="operator">(</span><span class="string">"CALL MyStoredProc(:param1, :param2)"</span><span class="operator">);</span>
query<span class="operator">.</span>bind<span class="operator">(</span><span class="string">":param1"</span><span class="operator">,</span><span class="string"> "myValue1"</span><span class="operator">);</span>
query<span class="operator">.</span>bind<span class="operator">(</span><span class="string">":param2"</span><span class="operator">,</span><span class="int"> 5024</span><span class="operator">,</span> QSql<span class="operator">::</span>InOut<span class="operator">);</span>
QSqlError daoError<span class="operator"> =</span> qx<span class="operator">::</span>dao<span class="operator">::</span>call_query<span class="operator">(</span>query<span class="operator">);</span>
QVariant vNewValue<span class="operator"> =</span> query<span class="operator">.</span>boundValue<span class="operator">(</span><span class="string">":param2"</span><span class="operator">);</span>
query<span class="operator">.</span>dumpSqlResult<span class="operator">();</span></pre>
</td>
</tr>
</tbody>
</table>
<br>
</td>
</tr>
</tbody>
</table>
<br><br>
<a name="faq_290"><u><b>Comment utiliser la classe <i>qx::QxDaoAsync</i> pour appeler des requ<71>tes de mani<6E>re
asynchrone (multi-thread) ?</b></u></a><br><br>
<table border="0" style="width: 100%" align="center">
<col>
<col>
<tbody>
<tr>
<td valign="middle" width="30"></td>
<td align="justify">
Il peut <20>tre parfois int<6E>ressant d'ex<65>cuter certaines requ<71>tes <20> la base de donn<6E>es de mani<6E>re
asynchrone (multi-thread), par exemple pour <20>viter de bloquer une IHM si une requ<71>te est trop longue <20>
s'ex<65>cuter.<br>
Pour simplifier les requ<71>tes asynchrones, la biblioth<74>que QxOrm fournit la classe <i><a
href="../doxygen/html/classqx_1_1_qx_dao_async.html" target="_blank">qx::QxDaoAsync</a></i>.<br>
Cette classe ex<65>cute une requ<71>te dans un thread d<>di<64> et renvoie un <i>SIGNAL</i>
<i>queryFinished()</i> lorsque la requ<71>te est termin<69>e.<br>
Pour utiliser la classe <i><a href="../doxygen/html/classqx_1_1_qx_dao_async.html"
target="_blank">qx::QxDaoAsync</a></i>, il suffit de :
<ul>
<li>v<EFBFBD>rifier que la requ<71>te fait appel <20> une classe qui impl<70>mente l'interface <i><a
href="../doxygen/html/classqx_1_1_ix_persistable.html"
target="_blank">qx::IxPersistable</a></i> ;</li>
<li>cr<EFBFBD>er une instance de type <i>qx::QxDaoAsync</i> (par exemple, une propri<72>t<EFBFBD> membre d'une classe
d<>rivant du type <i>QWidget</i>) ;</li>
<li>connecter un <i>SLOT</i> au <i>SIGNAL</i> <i>qx::QxDaoAsync::queryFinished()</i> (par exemple,
un <i>SLOT</i> d<>fini dans une classe d<>rivant du type <i>QWidget</i>) ;</li>
<li>ex<EFBFBD>cuter une requ<71>te <20> la base de donn<6E>es en utilisant l'une des m<>thodes commen<65>ant par
<i>async</i> : <i>qx::QxDaoAsync::asyncXXXX()</i>.
</li>
</ul>
Voici un exemple d'utilisation avec une classe nomm<6D>e <i>MyWidget</i> :<br>
<br>
<table border="1" bgcolor="#FFFFFF">
<col>
<tbody>
<tr>
<td>
<pre><span class="keyword">class</span> MyWidget<span class="operator"> :</span><span class="keyword"> public</span> QWidget<span class="operator">
{</span> Q_OBJECT<span class="comment">
//...
</span> qx<span class="operator">::</span>QxDaoAsync m_daoAsync<span class="operator">;</span><span class="comment">
//...
</span>Q_SLOTS<span class="operator">:</span><span class="type">
void</span> onQueryFinished<span class="operator">(</span><span class="keyword">const</span> QSqlError<span class="operator"> &amp;</span> daoError<span class="operator">,</span> qx<span class="operator">::</span>dao<span class="operator">::</span>detail<span class="operator">::</span>QxDaoAsyncParams_ptr pDaoParams<span class="operator">);</span><span class="comment">
//...
</span><span class="operator">};</span></pre>
</td>
</tr>
</tbody>
</table>
<br>
Et voici l'impl<70>mentation de la classe <i>MyWidget</i> :<br>
<br>
<table border="1" bgcolor="#FFFFFF">
<col>
<tbody>
<tr>
<td>
<pre>MyWidget<span class="operator">::</span>MyWidget<span class="operator">() :</span> QObject<span class="operator">()
{</span><span class="comment">
//...
</span> QObject<span class="operator">::</span>connect<span class="operator">((&amp;</span> m_daoAsync<span class="operator">),</span> SIGNAL<span class="operator">(</span>queryFinished<span class="operator">(</span><span class="keyword">const</span> QSqlError<span class="operator"> &amp;,</span> qx<span class="operator">::</span>dao<span class="operator">::</span>detail<span class="operator">::</span>QxDaoAsyncParams_ptr<span class="operator">)),</span><span class="keyword">
this</span><span class="operator">,</span> SLOT<span class="operator">(</span>onQueryFinished<span class="operator">(</span><span class="keyword">const</span> QSqlError<span class="operator"> &amp;,</span> qx<span class="operator">::</span>dao<span class="operator">::</span>detail<span class="operator">::</span>QxDaoAsyncParams_ptr<span class="operator">)));</span><span class="comment">
//...
</span><span class="operator">}</span><span class="type">
void</span> MyWidget<span class="operator">::</span>onQueryFinished<span class="operator">(</span><span class="keyword">const</span> QSqlError<span class="operator"> &amp;</span> daoError<span class="operator">,</span> qx<span class="operator">::</span>dao<span class="operator">::</span>detail<span class="operator">::</span>QxDaoAsyncParams_ptr pDaoParams<span class="operator">)
{</span><span class="flow">
if</span><span class="operator"> (!</span> pDaoParams<span class="operator">) {</span><span class="flow"> return</span><span class="operator">; }</span>
qx<span class="operator">::</span>QxSqlQuery query<span class="operator"> =</span> pDaoParams<span class="operator">-&gt;</span>query<span class="operator">;</span><span class="flow">
if</span><span class="operator"> (!</span> daoError<span class="operator">.</span>isValid<span class="operator">()) { ; }</span><span class="comment">
// If the async query is associated to a simple object, just use 'pDaoParams-&gt;pInstance' method
</span> qx<span class="operator">::</span>IxPersistable_ptr ptr<span class="operator"> =</span> pDaoParams<span class="operator">-&gt;</span>pInstance<span class="operator">;</span><span class="comment">
// If the async query is associated to a list of objects, just use 'pDaoParams-&gt;pListOfInstances' method
</span> qx<span class="operator">::</span>IxPersistableCollection_ptr lst<span class="operator"> =</span> pDaoParams<span class="operator">-&gt;</span>pListOfInstances<span class="operator">;</span><span class="comment">
//...
</span><span class="operator">}</span></pre>
</td>
</tr>
</tbody>
</table>
<br>
</td>
</tr>
</tbody>
</table>
<br><br>
<a name="faq_300"><u><b>Comment utiliser le module <i>QxModelView</i> pour travailler avec le moteur
<i>model/view</i> de Qt (Qt widgets et vues QML) ?</b></u></a><br><br>
<table border="0" style="width: 100%" align="center">
<col>
<col>
<tbody>
<tr>
<td valign="middle" width="30"></td>
<td align="justify">
Le module <b><a href="../doxygen/html/group___qx_model_view.html" target="_blank">QxModelView</a></b>
permet d'utiliser <a href="http://doc.qt.io/qt-5/modelview.html" target="_blank">le moteur model/view
de Qt</a> avec toutes les classes enregistr<74>es dans le contexte QxOrm :
<ul>
<li>Qt widgets : utilisation de <i>QTableView</i> ou <i>QListView</i> par exemple pour
afficher/modifier le contenu d'une table de base de donn<6E>es ;</li>
<li>QML : toute propri<72>t<EFBFBD> enregistr<74>e dans le contexte QxOrm est accessible en QML : le module <b><a
href="../doxygen/html/group___qx_model_view.html" target="_blank">QxModelView</a></b> permet
ainsi de faciliter l'int<6E>raction entre QML et les bases de donn<6E>es.</li>
</ul>
L'interface <a href="../doxygen/html/classqx_1_1_ix_model.html" target="_blank">qx::IxModel</a>
propose une base commune pour tous les mod<6F>les li<6C>s aux classes persistantes d<>clar<61>es dans le
contexte QxOrm. Les m<>thodes de cette classe pr<70>fix<69>es par '<i>qx</i>' appellent les fonctions du
namespace '<i>qx::dao</i>' et communiquent donc directement avec la base de donn<6E>es.<br />
<br />
Le projet de test <i>qxBlogModelView</i> pr<70>sent dans le dossier <i>./test/</i> du package QxOrm
montre comment cr<63>er rapidement un mod<6F>le et l'associer au moteur <i>model/view</i> de Qt (d'abord
dans un widget Qt, puis dans une vue QML).<br />
<br />
1- Exemple de cr<63>ation d'un mod<6F>le pour afficher/modifier les donn<6E>es de la table '<i>author</i>'
(voir le <a href="./tutorial.html" target="_blank">tutoriel <i>qxBlog</i></a> pour la d<>finition de la
classe '<i>author</i>') dans un QTableView :<br />
<br />
<table border="1" bgcolor="#FFFFFF">
<col>
<tbody>
<tr>
<td>
<pre><span class="comment">// Create a model and fetch all data from database
</span>qx<span class="operator">::</span>IxModel<span class="operator"> *</span> pModel<span class="operator"> =</span><span class="keyword"> new</span> qx<span class="operator">::</span>QxModel<span class="operator">&lt;</span>author<span class="operator">&gt;();</span>
pModel<span class="operator">-&gt;</span>qxFetchAll<span class="operator">();</span><span class="comment">
// Associate the model to a QTableView and display it
</span>QTableView tableView<span class="operator">;</span>
tableView<span class="operator">.</span>setModel<span class="operator">(</span>pModel<span class="operator">);</span>
tableView<span class="operator">.</span>show<span class="operator">();</span></pre>
</td>
</tr>
</tbody>
</table>
<br>
Ce qui donne le r<>sultat suivant <20> l'ex<65>cution :<br />
<br />
<img alt="qx_model_view_01" src="./resource/qx_model_view_01.png" border="0" /><br />
<br /><br />
2- Voici un autre exemple en QML (en Qt5, le module <b><a
href="../doxygen/html/group___qx_model_view.html" target="_blank">QxModelView</a></b> <20>tant
<20>galement compatible avec Qt4) :<br />
<br />
<table border="1" bgcolor="#FFFFFF">
<col>
<tbody>
<tr>
<td>
<pre><span class="comment">// Create a model and fetch all data from database
</span>qx<span class="operator">::</span>IxModel<span class="operator"> *</span> pModel<span class="operator"> =</span><span class="keyword"> new</span> qx<span class="operator">::</span>QxModel<span class="operator">&lt;</span>author<span class="operator">&gt;();</span>
pModel<span class="operator">-&gt;</span>qxFetchAll<span class="operator">();</span><span class="comment">
// Associate the model to a QML view and display it
</span>QQuickView qmlView<span class="operator">;</span>
qmlView<span class="operator">.</span>rootContext<span class="operator">()-&gt;</span>setContextProperty<span class="operator">(</span><span class="string">"myModel"</span><span class="operator">,</span> pModel<span class="operator">);</span>
qmlView<span class="operator">.</span>setSource<span class="operator">(</span>QUrl<span class="operator">(</span><span class="string">"qrc:/documents/main.qml"</span><span class="operator">));</span>
qmlView<span class="operator">.</span>show<span class="operator">();</span></pre>
</td>
</tr>
</tbody>
</table>
<br>
Et voici le contenu du fichier '<i>main.qml</i>' :<br />
<br />
<table border="1" bgcolor="#FFFFFF">
<col>
<tbody>
<tr>
<td>
<pre>import QtQuick<span class="float"> 2.1</span>
import QtQuick<span class="operator">.</span>Controls<span class="float"> 1.0</span>
Item<span class="operator"> {</span>
width<span class="operator">:</span><span class="int"> 400</span>
height<span class="operator">:</span><span class="int"> 300</span>
Row<span class="operator"> {</span>
height<span class="operator">:</span><span class="int"> 20</span>
spacing<span class="operator">:</span><span class="int"> 20</span>
Button<span class="operator"> {</span>
text<span class="operator">:</span><span class="string"> "Clear"</span>
onClicked<span class="operator">:</span> myModel<span class="operator">.</span>clear<span class="operator">()
}</span>
Button<span class="operator"> {</span>
text<span class="operator">:</span><span class="string"> "Fetch All"</span>
onClicked<span class="operator">:</span> myModel<span class="operator">.</span>qxFetchAll_<span class="operator">()
}</span>
Button<span class="operator"> {</span>
text<span class="operator">:</span><span class="string"> "Save"</span>
onClicked<span class="operator">:</span> myModel<span class="operator">.</span>qxSave_<span class="operator">()
}
}</span>
ListView<span class="operator"> {</span>
y<span class="operator">:</span><span class="int"> 30</span>
height<span class="operator">:</span><span class="int"> 270</span>
model<span class="operator">:</span> myModel
delegate<span class="operator">:</span> Row<span class="operator"> {</span>
height<span class="operator">:</span><span class="int"> 20</span>
spacing<span class="operator">:</span><span class="int"> 10</span>
Text<span class="operator"> {</span> text<span class="operator">:</span><span class="string"> "id: "</span><span class="operator"> +</span> author_id<span class="operator"> }</span>
TextField<span class="operator"> {</span>
text<span class="operator">:</span> name
onTextChanged<span class="operator">:</span> name<span class="operator"> =</span> text<span class="operator">
}
}
}
}</span></pre>
</td>
</tr>
</tbody>
</table>
<br>
Ce qui donne le r<>sultat suivant <20> l'ex<65>cution :<br />
<br />
<img alt="qx_model_view_02" src="./resource/qx_model_view_02.png" border="0" /><br />
<br />
Comme on peut le constater dans le fichier '<i>main.qml</i>', les propri<72>t<EFBFBD>s '<i>author_id</i>' et
'<i>name</i>' du mod<6F>le '<i>author</i>' (variable <i>myModel</i>) sont accessibles automatiquement en
lecture/<2F>criture (car elles ont <20>t<EFBFBD> enregistr<74>es dans le contexte QxOrm).<br />
De plus, l'interface <a href="../doxygen/html/classqx_1_1_ix_model.html"
target="_blank">qx::IxModel</a> propose une liste de m<>thodes accessibles en QML (utilisation de
<i>Q_INVOKABLE</i>) pour communiquer directement avec la base de donn<6E>es : ainsi, le bouton
'<i>Save</i>' de l'<27>cran ci-dessus enregistre le mod<6F>le en base de donn<6E>es depuis QML.<br />
<br />
<b>Remarque :</b> un plugin de <b>QxEntityEditor</b> permet de g<>n<EFBFBD>rer automatiquement le code des
mod<6F>les pour la gestion des relations. Il est ainsi possible de travailler avec des mod<6F>les
imbriqu<71>s.<br />
</td>
</tr>
</tbody>
</table>
<br><br>
</td>
</tr>
</tbody>
</table>
<br>
<hr style="width: 80%" align="center" size="1" color="#100D5A">
<table border="0" style="width: 80%" align="center">
<col>
<col>
<col>
<tbody>
<tr>
<td align="left" valign="middle">
<img alt="QxOrm" src="./resource/logo_qxorm_small.png" width="168" height="40">
</td>
<td align="center" valign="middle">
<font size="2"><EFBFBD> 2011-202XDL Teamty - <a href="mailto:ic-east.com">ic-east.com</a></font>
</td>
<td align="right" valign="middle">
<form action="https://www.paypal.com/cgi-bin/webscr" method="post">
<input type="hidden" name="cmd" value="_s-xclick">
<input type="hidden" name="hosted_button_id" value="2K4Z58ZYAYJ6S">
<input type="image" src="./resource/paypal_support_qxorm_library.gif" border="0" name="submit"
alt="Support QxOrm library - PayPal">
<img alt="" border="0" src="https://www.paypalobjects.com/fr_FR/i/scr/pixel.gif" width="1" height="1">
</form>
</td>
</tr>
</tbody>
</table>
</body>
</html>