3768 lines
301 KiB
HTML
3768 lines
301 KiB
HTML
<!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 >> 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 : </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<Key, Value></i> ?</a><br>
|
||
</li>
|
||
<li><a href="#faq_81">Pourquoi QxOrm fournit un nouveau type de pointeur intelligent
|
||
<i>qx::dao::ptr<T></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<Key,
|
||
Value></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<Key,
|
||
Value></i> ?<br>
|
||
<i><a href="../doxygen/html/classqx_1_1_qx_collection.html" target="_blank">qx::QxCollection<Key,
|
||
Value></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<T></i> ou
|
||
<i>QList<T></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<Key,
|
||
Value></i> ou <i>boost::unordered_map<Key, Value></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<Key, Value></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<Key, Value></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<Key, Value></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<Key, Value></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<Key, Value></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"><</span>drug<span class="operator">></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"><</span>QString<span class="operator">,</span> drug_ptr<span class="operator">></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">-></span>code<span class="operator"> =</span><span class="string"> "code1"</span><span class="operator">;</span> d1<span class="operator">-></span>name<span class="operator"> =</span><span class="string"> "name1"</span><span class="operator">;</span> d1<span class="operator">-></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">-></span>code<span class="operator"> =</span><span class="string"> "code2"</span><span class="operator">;</span> d2<span class="operator">-></span>name<span class="operator"> =</span><span class="string"> "name2"</span><span class="operator">;</span> d2<span class="operator">-></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">-></span>code<span class="operator"> =</span><span class="string"> "code3"</span><span class="operator">;</span> d3<span class="operator">-></span>name<span class="operator"> =</span><span class="string"> "name3"</span><span class="operator">;</span> d3<span class="operator">-></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">-></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">-></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">-></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">() <<</span> qPrintable<span class="operator">(</span>p<span class="operator">-></span>name<span class="operator">) <<</span><span class="string"> " "</span><span class="operator"> <<</span> qPrintable<span class="operator">(</span>p<span class="operator">-></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"> <</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">() <<</span> qPrintable<span class="operator">(</span>p<span class="operator">-></span>name<span class="operator">) <<</span><span class="string"> " "</span><span class="operator"> <<</span> qPrintable<span class="operator">(</span>p<span class="operator">-></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"><</span>QString<span class="operator">,</span> drug_ptr<span class="operator">></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">() <<</span> qPrintable<span class="operator">(</span>itr<span class="operator">.</span>value<span class="operator">()-></span>name<span class="operator">) <<</span><span class="string"> " "</span><span class="operator"> <<</span> qPrintable<span class="operator">(</span>itr<span class="operator">.</span>value<span class="operator">()-></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<T></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<T></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<T></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<T></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<Key, Value></i>.<br>
|
||
<br>
|
||
<b>Exemple d'utilisation du pointeur intelligent <i>qx::dao::ptr<T></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"><</span>blog<span class="operator">></span> blog_isdirty<span class="operator"> =</span> qx<span class="operator">::</span>dao<span class="operator">::</span>ptr<span class="operator"><</span>blog<span class="operator">>(</span><span class="keyword">new</span> blog<span class="operator">());</span>
|
||
blog_isdirty<span class="operator">-></span>m_id<span class="operator"> =</span> blog_1<span class="operator">-></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">() && !</span> blog_isdirty<span class="operator">.</span>isDirty<span class="operator">());</span>
|
||
|
||
blog_isdirty<span class="operator">-></span>m_text<span class="operator"> =</span><span class="string"> "blog property 'text' modified => 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"> && (</span>lstDiff<span class="operator">.</span>count<span class="operator">() ==</span><span class="int"> 1</span><span class="operator">) && (</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 => '%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">() && !</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"><</span> QList<span class="operator"><</span>author_ptr<span class="operator">> ></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"><</span>author_ptr<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>container_isdirty<span class="operator">);</span>
|
||
qAssert<span class="operator">(!</span> daoError<span class="operator">.</span>isValid<span class="operator">() && !</span> container_isdirty<span class="operator">.</span>isDirty<span class="operator">() && (</span>container_isdirty<span class="operator">-></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">-></span>at<span class="operator">(</span><span class="int">1</span><span class="operator">);</span>
|
||
author_ptr_dirty<span class="operator">-></span>m_name<span class="operator"> =</span><span class="string"> "author name modified at index 1 => 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"> && (</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 => '%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">-></span>at<span class="operator">(</span><span class="int">2</span><span class="operator">);</span>
|
||
author_ptr_dirty<span class="operator">-></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"> && (</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 => '%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">() && !</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">() <<</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">() && (</span>lst_blog_with_only_date_creation<span class="operator">.</span>size<span class="operator">() ></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">() ></span><span class="int"> 0</span><span class="operator">) && (</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">]-></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<T></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"><</span>QString<span class="operator">,</span><span class="type"> long</span><span class="operator">,</span> QString<span class="operator">></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"><</span>blog<span class="operator">></span> blog_ptr<span class="operator">;</span><span class="keyword">
|
||
typedef</span> std<span class="operator">::</span>vector<span class="operator"><</span>blog_ptr<span class="operator">></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"><</span><span class="int">0</span><span class="operator">>(</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"><</span><span class="int">1</span><span class="operator">>(</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"><</span><span class="int">2</span><span class="operator">>(</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"> &</span> s<span class="operator">) {</span> boost<span class="operator">::</span>tuples<span class="operator">::</span>get<span class="operator"><</span><span class="int">0</span><span class="operator">>(</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"><</span><span class="int">1</span><span class="operator">>(</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"> &</span> s<span class="operator">) {</span> boost<span class="operator">::</span>tuples<span class="operator">::</span>get<span class="operator"><</span><span class="int">2</span><span class="operator">>(</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"><</span>author<span class="operator">></span> author_ptr<span class="operator">;</span><span class="keyword">
|
||
typedef</span> qx<span class="operator">::</span>QxCollection<span class="operator"><</span>author<span class="operator">::</span>type_composite_key<span class="operator">,</span> author_ptr<span class="operator">></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 <QxOrm_Impl.h>
|
||
</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"> <></span><span class="type"> void</span> register_class<span class="operator">(</span>QxClass<span class="operator"><</span>author<span class="operator">> &</span> t<span class="operator">)
|
||
{</span>
|
||
t<span class="operator">.</span>id<span class="operator">(&</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">(&</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">(&</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">(&</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">(&</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"><</span><span class="type">int</span><span class="operator">>(&</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<T></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 => 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"> &</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"> &</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"> &</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"> &</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"> <></span><span class="keyword">
|
||
struct</span> QxDao_Trigger<span class="operator"><</span>BaseClassTrigger<span class="operator">>
|
||
{</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">-></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">-></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 <QxOrm_Impl.h>
|
||
</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"> <></span><span class="type"> void</span> register_class<span class="operator">(</span>QxClass<span class="operator"><</span>BaseClassTrigger<span class="operator">> &</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">(&</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">(&</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">(&</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">(&</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">(&</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<T></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"> <></span><span class="type"> void</span> register_class<span class="operator">(</span>QxClass<span class="operator"><</span>Bar<span class="operator">> &</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">(&</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">(&</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">-></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"><</span>Bar<span class="operator">>();</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"><</span>Bar<span class="operator">>();</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"><</span>Bar<span class="operator">>();</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) => 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 => 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) => 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 => 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<T>()</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 <boost/serialization/serialization.hpp>
|
||
#include <boost/serialization/split_free.hpp>
|
||
#include <boost/serialization/nvp.hpp>
|
||
</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"> <</span><span class="keyword">class</span> Archive<span class="operator">></span><span class="type">
|
||
void</span> save<span class="operator">(</span>Archive<span class="operator"> &</span> ar<span class="operator">,</span><span class="keyword"> const</span> ExtObject3D<span class="operator"> &</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"> <<</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"> <<</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"> <<</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"> <<</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"> <</span><span class="keyword">class</span> Archive<span class="operator">></span><span class="type">
|
||
void</span> load<span class="operator">(</span>Archive<span class="operator"> &</span> ar<span class="operator">,</span> ExtObject3D<span class="operator"> &</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"> >></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"> >></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"> >></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"> >></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<mon_objet></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"> <></span><span class="keyword"> struct</span> QxConvert_ToVariant<span class="operator"><</span> ExtObject3D<span class="operator"> > {</span><span class="keyword">
|
||
static inline</span> QVariant toVariant<span class="operator">(</span><span class="keyword">const</span> ExtObject3D<span class="operator"> &</span> t<span class="operator">,</span><span class="keyword"> const</span> QString<span class="operator"> &</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"> <></span><span class="keyword"> struct</span> QxConvert_FromVariant<span class="operator"><</span> ExtObject3D<span class="operator"> > {</span><span class="keyword">
|
||
static inline</span> qx_bool fromVariant<span class="operator">(</span><span class="keyword">const</span> QVariant<span class="operator"> &</span> v<span class="operator">,</span> ExtObject3D<span class="operator"> &</span> t<span class="operator">,</span><span class="keyword"> const</span> QString<span class="operator"> &</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<T>()</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<T>()</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"><</span>QString<span class="operator">,</span> IxClass<span class="operator"> *> *</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">-></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">-></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">()-></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">-></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">-></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"> <</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">-></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">-></span>getSqlRelation<span class="operator">();</span>
|
||
QString sInfos<span class="operator"> =</span> p<span class="operator">-></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">-></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">-></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">-></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<T>()</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<T>()</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"> &</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"> &</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"> &</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 <QxOrm_Impl.h>
|
||
</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"> <></span><span class="type"> void</span> register_class<span class="operator">(</span>QxClass<span class="operator"><</span>TestQtProperty<span class="operator">> &</span> t<span class="operator">)
|
||
{</span> qx<span class="operator">::</span>register_all_qt_properties<span class="operator"><</span>TestQtProperty<span class="operator">>(</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<T>()</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"><</span>author<span class="operator">></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"> <</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"><</span>author<span class="operator">></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"> <</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"> > :</span>age_3_0
|
||
OR last_name<span class="operator"> <> :</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"> <= :</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"><</span>T<span class="operator">>()</span>
|
||
qx<span class="operator">::</span>dao<span class="operator">::</span>fetch_by_query<span class="operator"><</span>T<span class="operator">>()</span>
|
||
qx<span class="operator">::</span>dao<span class="operator">::</span>update_by_query<span class="operator"><</span>T<span class="operator">>()</span>
|
||
qx<span class="operator">::</span>dao<span class="operator">::</span>delete_by_query<span class="operator"><</span>T<span class="operator">>()</span>
|
||
qx<span class="operator">::</span>dao<span class="operator">::</span>destroy_by_query<span class="operator"><</span>T<span class="operator">>()</span>
|
||
qx<span class="operator">::</span>dao<span class="operator">::</span>fetch_by_query_with_relation<span class="operator"><</span>T<span class="operator">>()</span>
|
||
qx<span class="operator">::</span>dao<span class="operator">::</span>fetch_by_query_with_all_relation<span class="operator"><</span>T<span class="operator">>()</span>
|
||
qx<span class="operator">::</span>dao<span class="operator">::</span>update_by_query_with_relation<span class="operator"><</span>T<span class="operator">>()</span>
|
||
qx<span class="operator">::</span>dao<span class="operator">::</span>update_by_query_with_all_relation<span class="operator"><</span>T<span class="operator">>()</span>
|
||
qx<span class="operator">::</span>dao<span class="operator">::</span>update_optimized_by_query<span class="operator"><</span>T<span class="operator">>()</span><span class="comment">
|
||
|
||
// avec la classe qx::QxSession
|
||
</span>qx<span class="operator">::</span>QxSession<span class="operator">::</span>count<span class="operator"><</span>T<span class="operator">>()</span>
|
||
qx<span class="operator">::</span>QxSession<span class="operator">::</span>fetchByQuery<span class="operator"><</span>T<span class="operator">>()</span>
|
||
qx<span class="operator">::</span>QxSession<span class="operator">::</span>update<span class="operator"><</span>T<span class="operator">>()</span>
|
||
qx<span class="operator">::</span>QxSession<span class="operator">::</span>deleteByQuery<span class="operator"><</span>T<span class="operator">>()</span>
|
||
qx<span class="operator">::</span>QxSession<span class="operator">::</span>destroyByQuery<span class="operator"><</span>T<span class="operator">>()</span><span class="comment">
|
||
|
||
// avec la classe qx::QxRepository<T>
|
||
</span>qx<span class="operator">::</span>QxRepository<span class="operator"><</span>T<span class="operator">>::</span>count<span class="operator">()</span>
|
||
qx<span class="operator">::</span>QxRepository<span class="operator"><</span>T<span class="operator">>::</span>fetchByQuery<span class="operator">()</span>
|
||
qx<span class="operator">::</span>QxRepository<span class="operator"><</span>T<span class="operator">>::</span>update<span class="operator">()</span>
|
||
qx<span class="operator">::</span>QxRepository<span class="operator"><</span>T<span class="operator">>::</span>deleteByQuery<span class="operator">()</span>
|
||
qx<span class="operator">::</span>QxRepository<span class="operator"><</span>T<span class="operator">>::</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<T>()</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<T></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<T></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"><</span> QList<span class="operator"><</span>author<span class="operator">> ></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"><</span> std<span class="operator">::</span>vector<span class="operator"><</span>blog<span class="operator">> ></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">-></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"><</span> QSharedPointer<span class="operator"><</span> std<span class="operator">::</span>vector<span class="operator"><</span>blog<span class="operator">> > >(</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<T></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 <QxOrm_Impl.h>
|
||
</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"> <></span><span class="type"> void</span> register_class<span class="operator">(</span>QxClass<span class="operator"><</span>DatabaseVersion<span class="operator">> &</span> t<span class="operator">)
|
||
{</span>
|
||
t<span class="operator">.</span>id<span class="operator">(&</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">(&</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"> <</span> qApp<span class="operator">-></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">-></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">()-></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"> >=</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"><</span>QString<span class="operator">,</span> qx<span class="operator">::</span>IxClass<span class="operator"> *> *</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"> <</span> pAllClasses<span class="operator">-></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">-></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">-></span>isKindOf<span class="operator">(</span><span class="string">"qx::service::IxParameter"</span><span class="operator">) ||</span> pClass<span class="operator">-></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 <= <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">-></span>getVersion<span class="operator">() <=</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">-></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">-></span>getName<span class="operator">() +</span><span class="string"> " ( ) WITH (OIDS = FALSE);"
|
||
"ALTER TABLE "</span><span class="operator"> +</span> pClass<span class="operator">-></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">-></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"> && (</span>l<span class="operator"> <</span> pDataMemberX<span class="operator">-></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">-></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">-></span>getVersion<span class="operator">() <=</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">-></span>getName<span class="operator">() +</span><span class="string"> " ADD COLUMN "</span><span class="operator"> +</span> p<span class="operator">-></span>getName<span class="operator">() +</span><span class="string"> " "</span><span class="operator"> +</span> p<span class="operator">-></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">-></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">-></span>getName<span class="operator">() +</span><span class="string"> " ADD PRIMARY KEY ("</span><span class="operator"> +</span> p<span class="operator">-></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">-></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">-></span>getName<span class="operator">() +</span><span class="string"> "_"</span><span class="operator"> +</span> p<span class="operator">-></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">-></span>getName<span class="operator">() +</span><span class="string"> " USING "</span><span class="operator"> +</span> p<span class="operator">-></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">-></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">-></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">-></span>getName<span class="operator">() +</span><span class="string"> " ALTER COLUMN "</span><span class="operator"> +</span> p<span class="operator">-></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">-></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">-></span>getName<span class="operator">() +</span><span class="string"> "_"</span><span class="operator"> +</span> p<span class="operator">-></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">-></span>getName<span class="operator">() +</span><span class="string"> "_"</span><span class="operator"> +</span> p<span class="operator">-></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">-></span>getName<span class="operator">() +</span><span class="string"> " ALTER COLUMN "</span><span class="operator"> +</span> p<span class="operator">-></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">-></span>getName<span class="operator">() +</span><span class="string"> "_"</span><span class="operator"> +</span> p<span class="operator">-></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">-></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">-></span>getName<span class="operator">() +</span><span class="string"> "."</span><span class="operator"> +</span> p<span class="operator">-></span>getName<span class="operator">() +</span><span class="string"> " IS $$"</span><span class="operator"> +</span> p<span class="operator">-></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 => 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"> &</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">() <<</span> sqlError<span class="operator">.</span>databaseText<span class="operator">();</span>
|
||
qDebug<span class="operator">() <<</span> sqlError<span class="operator">.</span>driverText<span class="operator">();</span>
|
||
qDebug<span class="operator">() <<</span> sqlError<span class="operator">.</span>number<span class="operator">();</span>
|
||
qDebug<span class="operator">() <<</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"> <-></span><span class="string"> "SMALLINT"
|
||
"qx_bool"</span><span class="operator"> <-></span><span class="string"> "SMALLINT"
|
||
"short"</span><span class="operator"> <-></span><span class="string"> "SMALLINT"
|
||
"int"</span><span class="operator"> <-></span><span class="string"> "INTEGER"
|
||
"long"</span><span class="operator"> <-></span><span class="string"> "INTEGER"
|
||
"long long"</span><span class="operator"> <-></span><span class="string"> "INTEGER"
|
||
"float"</span><span class="operator"> <-></span><span class="string"> "FLOAT"
|
||
"double"</span><span class="operator"> <-></span><span class="string"> "FLOAT"
|
||
"long double"</span><span class="operator"> <-></span><span class="string"> "FLOAT"
|
||
"unsigned short"</span><span class="operator"> <-></span><span class="string"> "SMALLINT"
|
||
"unsigned int"</span><span class="operator"> <-></span><span class="string"> "INTEGER"
|
||
"unsigned long"</span><span class="operator"> <-></span><span class="string"> "INTEGER"
|
||
"unsigned long long"</span><span class="operator"> <-></span><span class="string"> "INTEGER"
|
||
"std::string"</span><span class="operator"> <-></span><span class="string"> "TEXT"
|
||
"std::wstring"</span><span class="operator"> <-></span><span class="string"> "TEXT"
|
||
"QString"</span><span class="operator"> <-></span><span class="string"> "TEXT"
|
||
"QVariant"</span><span class="operator"> <-></span><span class="string"> "TEXT"
|
||
"QUuid"</span><span class="operator"> <-></span><span class="string"> "TEXT"
|
||
"QDate"</span><span class="operator"> <-></span><span class="string"> "DATE"
|
||
"QTime"</span><span class="operator"> <-></span><span class="string"> "TIME"
|
||
"QDateTime"</span><span class="operator"> <-></span><span class="string"> "TIMESTAMP"
|
||
"QByteArray"</span><span class="operator"> <-></span><span class="string"> "BLOB"
|
||
"qx::QxDateNeutral"</span><span class="operator"> <-></span><span class="string"> "TEXT"
|
||
"qx::QxTimeNeutral"</span><span class="operator"> <-></span><span class="string"> "TEXT"
|
||
"qx::QxDateTimeNeutral"</span><span class="operator"> <-></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"><</span>QString<span class="operator">,</span> QString<span class="operator">> *</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">-></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">-></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"> <></span><span class="type"> void</span> register_class<span class="operator">(</span>QxClass<span class="operator"><</span>MyClass<span class="operator">> &</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">(&</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">-></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<T></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<T></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"> &</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 <QxOrm_Impl.h>
|
||
</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"> <></span><span class="type"> void</span> register_class<span class="operator">(</span>QxClass<span class="operator"><</span>person<span class="operator">> &</span> t<span class="operator">)
|
||
{</span>
|
||
t<span class="operator">.</span>id<span class="operator">(&</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">(&</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">(&</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">(&</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">(&</span> person<span class="operator">::</span>_sex<span class="operator">,</span><span class="string"> "sex"</span><span class="operator">);</span>
|
||
|
||
QxValidatorX<span class="operator"><</span>person<span class="operator">> *</span> pAllValidator<span class="operator"> =</span> t<span class="operator">.</span>getAllValidator<span class="operator">();</span>
|
||
pAllValidator<span class="operator">-></span>add_NotEmpty<span class="operator">(</span><span class="string">"firstName"</span><span class="operator">);</span>
|
||
pAllValidator<span class="operator">-></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">-></span>add_CustomValidator<span class="operator">(&</span> person<span class="operator">::</span>isValid<span class="operator">);</span>
|
||
pAllValidator<span class="operator">-></span>add_CustomValidator_QVariant<span class="operator">(&</span> validateFirstName<span class="operator">,</span><span class="string"> "firstName"</span><span class="operator">);</span>
|
||
pAllValidator<span class="operator">-></span>add_CustomValidator_DataType<span class="operator"><</span>QDateTime<span class="operator">>(&</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"> &</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->add_CustomValidator(& 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">) && (</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"> &</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"> &</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"> &</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"> &</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"> &</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"> &</span> id<span class="operator"> =</span> QVariant<span class="operator">(),</span><span class="keyword"> const</span> QStringList<span class="operator"> &</span> columns<span class="operator"> =</span> QStringList<span class="operator">(),</span><span class="keyword"> const</span> QStringList<span class="operator"> &</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"> &</span> list<span class="operator">,</span><span class="keyword"> const</span> QStringList<span class="operator"> &</span> columns<span class="operator"> =</span> QStringList<span class="operator">(),</span><span class="keyword"> const</span> QStringList<span class="operator"> &</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"> &</span> query<span class="operator">,</span> qx<span class="operator">::</span>IxCollection<span class="operator"> &</span> list<span class="operator">,</span><span class="keyword"> const</span> QStringList<span class="operator"> &</span> columns<span class="operator"> =</span> QStringList<span class="operator">(),</span><span class="keyword"> const</span> QStringList<span class="operator"> &</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"> &</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"> &</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"> &</span> columns<span class="operator"> =</span> QStringList<span class="operator">(),</span><span class="keyword"> const</span> QStringList<span class="operator"> &</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"> &</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"> &</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"> &</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"> &</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"> &</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"> &</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"> &</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"><</span>qx<span class="operator">::</span>IxPersistable<span class="operator"> *></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">-></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"><</span>blog<span class="operator">></span> blog_ptr<span class="operator">;</span><span class="keyword">
|
||
typedef</span> std<span class="operator">::</span>vector<span class="operator"><</span>blog_ptr<span class="operator">></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"><</span>author<span class="operator">></span> author_ptr<span class="operator">;</span><span class="keyword">
|
||
typedef</span> qx<span class="operator">::</span>QxCollection<span class="operator"><</span>QString<span class="operator">,</span> author_ptr<span class="operator">></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"><QxOrm_Impl.h></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"> <></span><span class="type"> void</span> register_class<span class="operator">(</span>QxClass<span class="operator"><</span>author<span class="operator">> &</span> t<span class="operator">)
|
||
{</span>
|
||
t<span class="operator">.</span>id<span class="operator">(&</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">(&</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">(&</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">(&</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">(&</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"><</span><span class="type">int</span><span class="operator">>(&</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<T></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<T></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->list_blog->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"> <<</span><span class="string"> "author_id->list_blog->list_comment"</span><span class="operator">;</span>
|
||
relation<span class="operator"> <<</span><span class="string"> "author_id->list_blog->list_category"</span><span class="operator">;</span>
|
||
relation<span class="operator"> <<</span><span class="string"> "list_comment"</span><span class="operator">;</span>
|
||
relation<span class="operator"> <<</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">"*->*->*"</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<T>()</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<T>()</a> est une fonction <i>template</i> : le type T
|
||
doit <20>tre enregistr<74> dans le contexte QxOrm (fonction <i>qx::register_class<T></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">() ></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"> &</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">((&</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"> &,</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"> &,</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"> &</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">-></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->pInstance' method
|
||
</span> qx<span class="operator">::</span>IxPersistable_ptr ptr<span class="operator"> =</span> pDaoParams<span class="operator">-></span>pInstance<span class="operator">;</span><span class="comment">
|
||
// If the async query is associated to a list of objects, just use 'pDaoParams->pListOfInstances' method
|
||
</span> qx<span class="operator">::</span>IxPersistableCollection_ptr lst<span class="operator"> =</span> pDaoParams<span class="operator">-></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"><</span>author<span class="operator">>();</span>
|
||
pModel<span class="operator">-></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"><</span>author<span class="operator">>();</span>
|
||
pModel<span class="operator">-></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">()-></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> |