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

3606 lines
281 KiB
HTML
Raw Blame History

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=iso-8859-1">
<title>QxOrm : C++ Qt ORM Object Relational Mapping database library - QxEntityEditor : C++ Qt entities graphic editor
(data model designer and source code generator)</title>
<link rel='stylesheet' type='text/css' href='./resource/qxorm_style.css'>
<script type="text/javascript" src="./resource/jquery.min.js"></script>
<script type="text/javascript" src="./resource/qxorm_script.js"></script>
</head>
<body>
<table border="0" style="width: 80%" align="center">
<col>
<col>
<col>
<col>
<col>
<tbody>
<tr>
<td><a href="./home.html"><img alt="QxOrm" src="./resource/logo_qxorm_and_qxee.png" align="left" border="0"></a>
</td>
<td align="right" style="vertical-align:bottom">
<div id="qx_search">
<gcse:search></gcse:search>
</div>
</td>
<td width="15"></td>
<td align="right" style="vertical-align:bottom">
<img alt="Windows" src="./resource/logo_windows.gif" width="35" height="35">
<img alt="Linux" src="./resource/logo_linux.gif" width="35" height="35">
<img alt="Macintosh" src="./resource/logo_mac.gif" width="35" height="35">
</td>
<td width="70"><img alt="C++" src="./resource/logo_cpp.gif" width="50" height="50" align="right"></td>
</tr>
</tbody>
</table>
<hr style="width: 80%" align="center" size="1" color="#100D5A">
<table border="0" style="width: 80%" align="center">
<col>
<col>
<col>
<col>
<col>
<col>
<tbody>
<tr>
<td align="center"><a href="./home.html" class="btn_nav">Home</a></td>
<td align="center"><a href="./download.html" class="btn_nav">Download</a></td>
<td align="center"><a href="./quick_sample.html" class="btn_nav">Quick sample</a></td>
<td align="center" onmouseover="showHideElementById('menu_tuto', true);"
onmouseout="showHideElementById('menu_tuto', false);">
<a href="./tutorial.html" class="btn_nav">Tutorial (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">Manual (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">QxOrm manual</a><br />
<a href="./manual_qxee.html" class="btn_sub_menu">QxEntityEditor manual</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">Our customers</a></td>
</tr>
</tbody>
</table>
<hr style="width: 80%" align="center" size="1" color="#100D5A">
<table border="0" style="width: 80%" align="center">
<col>
<col>
<col>
<col>
<col>
<col>
<tbody>
<tr>
<td align="left" valign="top">
<font size="2" class="txt_with_shadow">QxOrm &gt;&gt; Faq</font>
</td>
<td align="right" valign="top">
<table cellspacing="0" cellpadding="1">
<col>
<col>
<tbody>
<tr>
<td align="right" valign="top">
<font size="2" class="txt_with_shadow">Current version :&nbsp;</font>
</td>
<td align="left" valign="top">
<font size="2" class="txt_with_shadow">QxOrm 1.5.0 - <a href="../doxygen/index.html"
target="_blank">QxOrm library online class documentation</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">What is QxOrm ?</a><br>
</li>
<li><a href="#faq_15">What is QxEntityEditor ?</a><br>
</li>
<li><a href="#faq_20">How to contact QxOrm to report a bug or ask a question ?</a><br>
</li>
<li><a href="#faq_30">How to install and build QxOrm library ?</a><br>
</li>
<li><a href="#faq_40">What are the databases supported by QxOrm ?</a><br>
</li>
<li><a href="#faq_50">Why QxOrm is dependent on two libraries : boost and Qt ?</a><br>
</li>
<li><a href="#faq_60">Why does QxOrm require a precompiled header to be used ?</a><br>
</li>
<li><a href="#faq_70">Is it possible to reduce compilation times of my project ?</a><br>
</li>
<li><a href="#faq_75">What are all types of <i>serialization</i> available ?</a><br>
</li>
<li><a href="#faq_80">Why does QxOrm provide a new type of container <i>qx::QxCollection&lt;Key,
Value&gt;</i> ?</a><br>
</li>
<li><a href="#faq_81">Why does QxOrm provide a new smart-pointer <i>qx::dao::ptr&lt;T&gt;</i>
?</a><br>
</li>
<li><a href="#faq_90">Should I use <i>QString</i> or <i>std::string</i> ?</a><br>
</li>
<li><a href="#faq_95">Is it necessary to use <i>smart-pointers</i> ?</a><br>
</li>
<li><a href="#faq_100">The primary key is <i>long</i> type by default. Is it possible to use a key
of <i>QString</i> type or other ?</a><br>
</li>
<li><a href="#faq_101">How to define a '<i>multi-columns primary key</i>' (<i>composite key</i>)
?</a><br>
</li>
<li><a href="#faq_105">How to register <i>private</i> or <i>protected</i> members into QxOrm context
?</a><br>
</li>
<li><a href="#faq_110">How to enable/disable the module <i>QxMemLeak</i> for automatic detection of
memory leaks ?</a><br>
</li>
<li><a href="#faq_120">How to manage inheritance and database ?</a><br>
</li>
<li><a href="#faq_130">How to define a '<i>Trigger</i>' with QxOrm ?</a><br>
</li>
<li><a href="#faq_140">How to register an abstract class into QxOrm context ?</a><br>
</li>
<li><a href="#faq_150">How to register a class defined into a namespace into QxOrm context ?</a><br>
</li>
<li><a href="#faq_160">How to define a soft delete behavior ?</a><br>
</li>
<li><a href="#faq_170">How to use a session (<i>qx::QxSession</i> class) to manage automatically
database transactions (using C++ RAII) ?</a><br>
</li>
<li><a href="#faq_180">How to persist a type without its source code (class from an external library
for example) ?</a><br>
</li>
<li><a href="#faq_190">How to use introspection engine (or reflection engine) of QxOrm library
?</a><br>
</li>
<li><a href="#faq_200">How to register automatically Qt meta-properties (using <i>Q_PROPERTY</i>
macro) to QxOrm context ?</a><br>
</li>
<li><a href="#faq_210">How to build a query without writing SQL with the class <i>qx::QxSqlQuery</i>
?</a><br>
</li>
<li><a href="#faq_220">How to use the cache (functions into <i>namespace</i> <i>qx::cache</i>) of
QxOrm library ?</a><br>
</li>
<li><a href="#faq_230">How to build SQL schema (create and update tables) based on C++ persistents
classes registered in QxOrm context ?</a><br>
</li>
<li><a href="#faq_240">How to associate a SQL type to a C++ class ?</a><br>
</li>
<li><a href="#faq_250">How to use <i>QxValidator</i> module to validate automatically an instance
?</a><br>
</li>
<li><a href="#faq_260">How to use <i>qx::IxPersistable</i> interface ?</a><br>
</li>
<li><a href="#faq_270">How to use relationship engine to fetch datas from many tables ?</a><br>
</li>
<li><a href="#faq_280">How to execute a stored procedure or a custom SQL query ?</a><br>
</li>
<li><a href="#faq_290">How to use <i>qx::QxDaoAsync</i> class to execute queries in asynchronous way
(multi-thread) ?</a><br>
</li>
<li><a href="#faq_300">How to use <i>QxModelView</i> module to interact with Qt <i>model/view</i>
architecture (Qt widgets and/or QML views) ?</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>What is 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 is a C++ library designed to provide <i>Object Relational Mapping (ORM)</i> feature to C++
users.<br>
QxOrm is developed by XDL Team, a software development engineer since 2003.</b>
<br>
<b>QxOrm</b> provides many functionalities starting from a simple <i>C++ setting function by class</i>
:
<ul>
<li><b>
<font style="background-color:yellow">persistence</font>
</b> : communication with databases (support <i>1-1</i>, <i>1-n</i>, <i>n-1</i> and <i>n-n</i>
relationships)
</li>
<li><b>
<font style="background-color:yellow">serialization</font>
</b> : binary, XML and JSON format
</li>
<li><b>
<font style="background-color:yellow">reflection</font>
</b> (or <b>
<font style="background-color:yellow">introspection</font>
</b>) : access to classes definitions, retrieve properties and call classes methods
</li>
</ul>
</td>
</tr>
</tbody>
</table>
<br>
<a name="faq_15"><u><b>What is 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> is a graphic editor for <b>QxOrm</b> library : <b>QxEntityEditor</b> provides a
graphic way to manage the data model.<br>
<b>QxEntityEditor</b> is multi-platform (available for Windows, Linux and Mac OS X) and generates
native code for all environments : desktop (Windows, Linux, Mac OS X), embedded and mobile (Android,
iOS, Windows Phone, Raspberry Pi, etc.).<br>
<a href="./tutorial_4.html">A presentation video of <b>QxEntityEditor</b> application is
available</a>.<br>
<br>
<b>QxEntityEditor</b> is based on plugins and provides many ways to import/export your data model :
<ul>
<li>generate C++ persistent classes automatically (registered in QxOrm context) ;</li>
<li>generate DDL SQL script automatically (database schema) for SQLite, MySQL, PostgreSQL, Oracle
and MS SQL Server ;</li>
<li>manage schema evolution for each project version (<i>ALTER TABLE</i>, <i>ADD COLUMN</i>, <i>DROP
INDEX</i>, etc.) ;</li>
<li>transfer your data model over network and create quickly client/server applications, using <a
href="../doxygen/html/group___qx_service.html" target="_blank">QxService</a> module ;</li>
<li>import existing database structure (using ODBC connection) for SQLite, MySQL, PostgreSQL, Oracle
and MS SQL Server databases ;</li>
<li>because each project is different, QxEntityEditor provides several ways to customize generated
files (especially a javascript engine and an integrated debugger).</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> is developed by XDL Team, a software development engineer since 2003.<br>
<br><br>
</td>
</tr>
</tbody>
</table>
<br>
<a name="faq_20"><u><b>How to contact QxOrm to report a bug or ask a 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">
If you find a bug or if you have a question about <b>QxOrm</b> library, you can send an e-mail to :
<u><i>support@qxorm.com</i></u>.<br>
A forum dedicated to <b>QxOrm</b> is available <a href="https://www.qxorm.com/forum/phpbb/"
target="_blank">here</a>.
</td>
</tr>
</tbody>
</table>
<br><br>
<a name="faq_30"><u><b>How to install and build QxOrm library ?</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">A tutorial to install a development environment with QxOrm library on
Windows is available.</a><br />
<br />
<b>QxOrm</b> uses <b>qmake</b> process from <b>Qt</b> library to create <i>makefile</i> and build the
project.<br>
<b>qmake</b> is portable and multi-platform, so it works perfectly on Windows, Linux (Unix) and
Mac.<br>
To build <b>QxOrm</b> library, just execute following commands :<br>
<i>qmake</i><br>
<i>make debug</i><br>
<i>make release</i><br>
<br>
On <b>Windows</b>, <i>*.vcproj</i> and <i>*.sln</i> files are available for <b>Visual C++ 2008</b>,
<b>Visual C++ 2010</b> and <b>Visual C++ 2012</b>.<br>
<i>*.pro</i> files are readable by <b>Qt Creator</b>, and some plugins are available to interface to
other C++ IDE.<br>
<i>mingw_build_all_debug.bat</i> and <i>mingw_build_all_release.bat</i> scripts in the directory
<i>./tools/</i> can quickly built QxOrm library and all tests with <b>MinGW</b> compiler on
Windows.<br>
<i>gcc_build_all_debug.sh</i> and <i>gcc_build_all_release.sh</i> scripts in the directory
<i>./tools/</i> can quickly built QxOrm library and all tests with <b>GCC</b> compiler on
<b>Linux</b>.<br>
<i>osx_build_all_debug.sh</i> and <i>osx_build_all_release.sh</i> scripts in the directory
<i>./tools/</i> can quickly built QxOrm library and all tests on <b>Mac</b> (thanks very much to
Dominique Billet).<br>
<br>
<b>Note :</b> depending on your development environment, it may be necessary to modify
<u><b>QxOrm.pri</b></u> file to set <b>boost</b> package configuration :<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>What are the databases supported by 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> uses the engine <a href="http://doc.qt.io/qt-5/qtsql-index.html"
target="_blank"><i>QtSql</i></a> of <b>Qt</b> based on a system of plug-in.<br>
A detailed list of supported databases is available on the website of Qt <a
href="http://doc.qt.io/qt-5/sql-driver.html" target="_blank">here</a>.<br> The plug-in <i>ODBC</i>
(<i>QODBC</i>) ensures compatibility with many databases.<br> For optimal performances, it is possible
to use a plug-in specific to a database :
<ul>
<li><i>QMYSQL</i> : MySQL
</li>
<li><i>QPSQL</i> : PostgreSQL (versions 7.3 and above)
</li>
<li><i>QOCI</i> : Oracle Call Interfaces 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>Why QxOrm is dependent on two libraries : boost and 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> uses many functionalities available in excellent libraries : <b>boost</b> and
<b>Qt</b>.<br>
In addition, these two libraries are used in many projects both professional and open source.<br>
A large number of forums, tutorials, and a whole community are available to answer any issue that
could arise.<br>
The <b>QxOrm</b> objective is not to redevelop features that already exist but to provide a powerful
tool for access to databases such as it exists in other languages (<i>Java</i> with <i>Hibernate</i>,
<i>.Net</i> with <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> : cross-platform application development framework : GUI
(<i>QtGui</i>), network (<i>QtNetwork</i>), XML (<i>QtXml</i>), database (<i>QtSql</i>)...<br>
Qt provides excellent support and documentation. Using Qt, you can write simple and powerful
C++ code.<br>
Qt is produced by Digia's Qt Development Frameworks division and is available under LGPL
license.<br>
QxOrm is compatible with many Qt's objects : <i>QObject, QString, QDate, QTime, QDateTime,
QList, QHash, QSharedPointer, QScopedPointer...</i><br>
It is recommended to install the latest version of Qt available at the following address : <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> : many of boost's founders are on the C++ standard committee
and several boost libraries have been accepted for incorporation into C++1x (new standard for
the C++ programming language).
The boost's libraries are aimed at a wide range of C++ users and application domains.<br>
QxOrm uses the following boost's features (header files <i>*.hpp</i> only, boost
<i>serialization</i> dependency is optional) : <i>smart_pointer, type_traits,
multi_index_container, unordered_container, any, tuple, foreach, function.</i><br>
It is recommended to get the latest version of boost available at the following address : <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>Why does QxOrm require a precompiled header to be used ?</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> uses the techniques of <b>C++ meta-programming</b> to provide most of its
functionalities.<br>
You do not need to know how to use meta-programming to work with <b>QxOrm</b> library.<br>
Indeed, QxOrm is simple to use and the C++ code written with Qt and QxOrm is easy to read, therefore
easy to develop and to maintain.<br><br>
However, meta-programming is costly in compilation times.<br>
By using a <i>precompiled.h</i> file, your project will be compiled much more quickly.<br>
Last but not least, another advantage is that the file <i>QxOrm.h</i> includes the basic
functionalities of libraries boost and Qt.<br>
It is thus not necessary anymore to write <i>#include &lt;QtCore/QString.h&gt;</i> to use the class
QString of Qt for example.<br>
In the same way, there is no need anymore to write <i>#include &lt;boost/shared_ptr.hpp&gt;</i> to use
smart pointers of boost library.
</td>
</tr>
</tbody>
</table>
<br><br>
<a name="faq_70"><u><b>Is it possible to reduce compilation times of my project ?</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">
Yes, if the <i>serialization</i> of your data in <i>XML</i> format is not used in your project, you
can disable this functionality.<br>
The compilation times will be then reduced but you will not have anymore access to the namespace
<i>qx::serialization:xml</i>.<br>
To disable <i>XML serialization</i>, it is necessary to open the <i>QxOrm.pri</i> config file and to
remove (or comment) the compilation option <b><i>_QX_ENABLE_BOOST_SERIALIZATION_XML</i></b>.<br>
A recompilation of QxOrm library is necessary to take into account this modification.<br>
<br>
Another possibility is to use the <i>polymorphic</i> classes of the library <a
href="http://www.boost.org/doc/libs/release/libs/serialization/doc/index.html"
target="_blank"><i>boost::serialization</i></a> (instead of <i>template</i>).<br>
This feature reduces compilation times and the size of the executable that is generated.<br>
However, the speed of execution of your program will be reduced since part of the work carried out
during compilation will be done during the execution of your application.<br>
To use this feature with <b>QxOrm</b>, you must enable the compilation option
<b><i>_QX_ENABLE_BOOST_SERIALIZATION_POLYMORPHIC</i></b> in the <i>QxOrm.pri</i> config file.<br>
<b>Warning</b> : the <i>serialization</i> functions will be then accessible from the following
<i>namespace</i> : <i>qx::serialization::polymorphic_binary</i>,
<i>qx::serialization::polymorphic_text</i> and <i>qx::serialization::polymorphic_xml</i>.<br>
A recompilation of QxOrm library is necessary to take into account this modification.<br>
<br>
It is also possible to use <i>Q_PROPERTY</i> macro to define properties for a class inherited from
<i>QObject</i> type.<br>
In this case, there is two different ways to register properties in QxOrm context and you can reduce
noticeably compilation times of your project.<br>
For more details about this feature, <a href="./faq.html#faq_200">click here</a>.<br>
<br>
<b>Note :</b> it is important to check if all optimizations provided by the compiler are enabled, for
example to compile using several processors :
<ul>
<li><b>MSVC++</b> : use environment variable <b>SET CL=/MP</b></li>
<li><b>GCC</b> and <b>Clang</b> : put processors count as parameter to the <i>make</i> process, for
example to use 8 processors : <b>SET MAKE_COMMAND=make -j8</b></li>
</ul>
</td>
</tr>
</tbody>
</table>
<br><br>
<a name="faq_75"><u><b>What are all types of <i>serialization</i> available ?</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> is based on <a
href="http://www.boost.org/doc/libs/release/libs/serialization/doc/index.html" target="_blank">boost
<i>serialization</i></a> library.<br>
There are several types of serialization available : <i>binary, XML, text, etc...</i><br>
<i>QxOrm.pri</i> config file can enable and/or disable some types of serialization.<br>
<br>
Each type of serialization has its own characteristics :<br>
* <b>binary</b> : <i>smallest, fastest, non-portable</i><br>
* <b>text</b> : <i>larger, slower, portable</i><br>
* <b>XML</b> : <i>largest, slowest, portable</i><br>
<br>
<b>Note :</b> <b>binary</b> type is not portable, so you can't transfer data between Windows and Unix
for example.<br>
If you need to transfer data over network between different platforms, you have to use <b>text</b> or
<b>XML</b> serialization.<br>
<b>QxOrm</b> provides another solution : <b><a href="http://epa.codeplex.com/"
target="_blank">portable_binary</a></b> serialization.<br>
<b>portable_binary</b> has the same characteristics as <b>binary</b> type and can serialize data in a
portable way.<br>
However, <b>portable_binary</b> is not provided officially by <b>boost</b> library, so it's necessary
to test before using in a production software.
</td>
</tr>
</tbody>
</table>
<br><br>
<a name="faq_80"><u><b>Why does QxOrm provide a new type of container <i>qx::QxCollection&lt;Key,
Value&gt;</i> ?</b></u></a><br><br>
<table border="0" style="width: 100%" align="center">
<col>
<col>
<tbody>
<tr>
<td valign="middle" width="30"></td>
<td align="justify">
There are many containers in <b>stl</b>, <b>boost</b> and <b>Qt</b> libraries.<br>
It is therefore legitimate to ask this question : what is <i>qx::QxCollection&lt;Key, Value&gt;</i>
?<br>
<i><a href="../doxygen/html/classqx_1_1_qx_collection.html" target="_blank">qx::QxCollection&lt;Key,
Value&gt;</a></i> is a new <i>container</i> (based on the excellent library <a
href="http://www.boost.org/doc/libs/release/libs/multi_index/doc/index.html"
target="_blank"><i>boost::multi_index_container</i></a>) which has the following functionalities :
<ul>
<li>preserves the insertion order of elements in the list
</li>
<li>quick access to an element by its index : is equivalent to <i>std::vector&lt;T&gt;</i> or
<i>QList&lt;T&gt;</i> for example
</li>
<li>quick access to an element by a key (<i>hash-map</i>) : is equivalent to <i>QHash&lt;Key,
Value&gt;</i> or <i>boost::unordered_map&lt;Key, Value&gt;</i> for example
</li>
<li>sort by <i>Key</i> type and by <i>Value</i> type</li>
</ul>
<b>Note :</b> <i>qx::QxCollection&lt;Key, Value&gt;</i> is compatible with the <i>foreach</i> macro
provided by <b>Qt</b> library and the <a
href="http://www.boost.org/doc/libs/release/doc/html/foreach.html"
target="_blank"><i>BOOST_FOREACH</i></a> macro provided by <b>boost</b> library.<br>
However, each element returned by these 2 macros corresponds to an object of type <i>std::pair&lt;Key,
Value&gt;</i>.<br>
To obtain a more natural and more readable result, it is advised to use the <i>_foreach</i> macro :
this macro uses <i>BOOST_FOREACH</i> for all the containers except for <i>qx::QxCollection&lt;Key,
Value&gt;</i>.<br>
In this case, the returned element corresponds to the <i>Value</i> type (cf. <i>sample</i>).<br>
The macro <i>_foreach</i> is compatible with all <i>containers</i> (<b>stl</b>, <b>Qt</b>,
<b>boost</b>...) since it uses the macro <i>BOOST_FOREACH</i>.<br><br>
<b>Additional note :</b> <i>qx::QxCollection&lt;Key, Value&gt;</i> is particularly suited to receive
data resulting from a database.<br> Indeed, these data can be sorted (by using <i>ORDER BY</i> in a
sql request for example), it is thus important to preserve the insertion order of the elements in the
list.<br>
Furthermore, each data resulting from a database has a unique id. It is thus important to be able to
access quickly to an element based on this single identifier (<i>hash-map</i>).<br><br>
<b>Sample :</b><br>
<table border="1" bgcolor="#FFFFFF">
<col>
<tbody>
<tr>
<td>
<pre><span class="comment">/* definition of drug class with 3 properties : 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">
/* smart pointer of drug */</span><span class="keyword">
typedef</span> boost<span class="operator">::</span>shared_ptr<span class="operator">&lt;</span>drug<span class="operator">&gt;</span> drug_ptr<span class="operator">;</span><span class="comment">
/* collection of drugs by code */</span>
qx<span class="operator">::</span>QxCollection<span class="operator">&lt;</span>QString<span class="operator">,</span> drug_ptr<span class="operator">&gt;</span> lstDrugs<span class="operator">;</span><span class="comment">
/* create 3 new drugs */</span>
drug_ptr d1<span class="operator">;</span> d1<span class="operator">.</span>reset<span class="operator">(</span><span class="keyword">new</span> drug<span class="operator">());</span> d1<span class="operator">-&gt;</span>code<span class="operator"> =</span><span class="string"> "code1"</span><span class="operator">;</span> d1<span class="operator">-&gt;</span>name<span class="operator"> =</span><span class="string"> "name1"</span><span class="operator">;</span> d1<span class="operator">-&gt;</span>desc<span class="operator"> =</span><span class="string"> "desc1"</span><span class="operator">;</span>
drug_ptr d2<span class="operator">;</span> d2<span class="operator">.</span>reset<span class="operator">(</span><span class="keyword">new</span> drug<span class="operator">());</span> d2<span class="operator">-&gt;</span>code<span class="operator"> =</span><span class="string"> "code2"</span><span class="operator">;</span> d2<span class="operator">-&gt;</span>name<span class="operator"> =</span><span class="string"> "name2"</span><span class="operator">;</span> d2<span class="operator">-&gt;</span>desc<span class="operator"> =</span><span class="string"> "desc2"</span><span class="operator">;</span>
drug_ptr d3<span class="operator">;</span> d3<span class="operator">.</span>reset<span class="operator">(</span><span class="keyword">new</span> drug<span class="operator">());</span> d3<span class="operator">-&gt;</span>code<span class="operator"> =</span><span class="string"> "code3"</span><span class="operator">;</span> d3<span class="operator">-&gt;</span>name<span class="operator"> =</span><span class="string"> "name3"</span><span class="operator">;</span> d3<span class="operator">-&gt;</span>desc<span class="operator"> =</span><span class="string"> "desc3"</span><span class="operator">;</span><span class="comment">
/* insert drugs into the collection */</span>
lstDrugs<span class="operator">.</span>insert<span class="operator">(</span>d1<span class="operator">-&gt;</span>code<span class="operator">,</span> d1<span class="operator">);</span>
lstDrugs<span class="operator">.</span>insert<span class="operator">(</span>d2<span class="operator">-&gt;</span>code<span class="operator">,</span> d2<span class="operator">);</span>
lstDrugs<span class="operator">.</span>insert<span class="operator">(</span>d3<span class="operator">-&gt;</span>code<span class="operator">,</span> d3<span class="operator">);</span><span class="comment">
/* iterate with '_foreach' keyword */</span>
_foreach<span class="operator">(</span>drug_ptr p<span class="operator">,</span> lstDrugs<span class="operator">)
{</span> qDebug<span class="operator">() &lt;&lt;</span> qPrintable<span class="operator">(</span>p<span class="operator">-&gt;</span>name<span class="operator">) &lt;&lt;</span><span class="string"> " "</span><span class="operator"> &lt;&lt;</span> qPrintable<span class="operator">(</span>p<span class="operator">-&gt;</span>desc<span class="operator">); }</span><span class="comment">
/* iterate with 'for' keyword */</span><span class="flow">
for</span><span class="operator"> (</span><span class="type">long</span> l<span class="operator"> =</span><span class="int"> 0</span><span class="operator">;</span> l<span class="operator"> &lt;</span> lstDrugs<span class="operator">.</span>count<span class="operator">(); ++</span>l<span class="operator">)
{</span>
drug_ptr p<span class="operator"> =</span> lstDrugs<span class="operator">.</span>getByIndex<span class="operator">(</span>l<span class="operator">);</span>
QString code<span class="operator"> =</span> lstDrugs<span class="operator">.</span>getKeyByIndex<span class="operator">(</span>l<span class="operator">);</span>
qDebug<span class="operator">() &lt;&lt;</span> qPrintable<span class="operator">(</span>p<span class="operator">-&gt;</span>name<span class="operator">) &lt;&lt;</span><span class="string"> " "</span><span class="operator"> &lt;&lt;</span> qPrintable<span class="operator">(</span>p<span class="operator">-&gt;</span>desc<span class="operator">);
}</span><span class="comment">
/* iterate with 'QxCollectionIterator' java style */</span>
qx<span class="operator">::</span>QxCollectionIterator<span class="operator">&lt;</span>QString<span class="operator">,</span> drug_ptr<span class="operator">&gt;</span> itr<span class="operator">(</span>lstDrugs<span class="operator">);</span><span class="flow">
while</span><span class="operator"> (</span>itr<span class="operator">.</span>next<span class="operator">())
{</span>
QString code<span class="operator"> =</span> itr<span class="operator">.</span>key<span class="operator">();</span>
qDebug<span class="operator">() &lt;&lt;</span> qPrintable<span class="operator">(</span>itr<span class="operator">.</span>value<span class="operator">()-&gt;</span>name<span class="operator">) &lt;&lt;</span><span class="string"> " "</span><span class="operator"> &lt;&lt;</span> qPrintable<span class="operator">(</span>itr<span class="operator">.</span>value<span class="operator">()-&gt;</span>desc<span class="operator">);
}</span><span class="comment">
/* sort ascending by key and sort descending by value */</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">
/* access drug by 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">
/* access drug by index */</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">
/* test if drug exists and if collection is empty */</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">
/* remove the second drug from collection */</span>
lstDrugs<span class="operator">.</span>removeByIndex<span class="operator">(</span><span class="int">2</span><span class="operator">);</span><span class="comment">
/* remove the drug with "code3" */</span>
lstDrugs<span class="operator">.</span>removeByKey<span class="operator">(</span><span class="string">"code3"</span><span class="operator">);</span><span class="comment">
/* clear the 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>Why does QxOrm provide a new smart-pointer <i>qx::dao::ptr&lt;T&gt;</i>
?</b></u></a><br><br>
<table border="0" style="width: 100%" align="center">
<col>
<col>
<tbody>
<tr>
<td valign="middle" width="30"></td>
<td align="justify">
<b>QxOrm</b> can be used with smart-pointers of <b>boost</b> and <b>Qt</b> libraries.<br>
<b>QxOrm</b> smart-pointer is based on <i>QSharedPointer</i> and provides new features with
'<i>qx::dao::...</i>' functions.<br>
<i><a href="../doxygen/html/classqx_1_1dao_1_1ptr.html" target="_blank">qx::dao::ptr&lt;T&gt;</a></i>
keeps automatically values from database.<br>
So it's possible to detect if an instance has been modified using the method '<i>isDirty()</i>' : this
method can return list of properties changed.<br>
<i>qx::dao::ptr&lt;T&gt;</i> can also be used with the function '<i>qx::dao::update_optimized()</i>'
to update in database only properties changed.<br>
<i>qx::dao::ptr&lt;T&gt;</i> can be used with a simple object and with many containers : <i>stl</i>,
<i>boost</i>, <i>Qt</i> and <i>qx::QxCollection&lt;Key, Value&gt;</i>.<br>
<br>
<b>Sample :</b><br>
<table border="1" bgcolor="#FFFFFF">
<col>
<tbody>
<tr>
<td>
<pre><span class="comment"> // Test 'isDirty()' method
</span> qx<span class="operator">::</span>dao<span class="operator">::</span>ptr<span class="operator">&lt;</span>blog<span class="operator">&gt;</span> blog_isdirty<span class="operator"> =</span> qx<span class="operator">::</span>dao<span class="operator">::</span>ptr<span class="operator">&lt;</span>blog<span class="operator">&gt;(</span><span class="keyword">new</span> blog<span class="operator">());</span>
blog_isdirty<span class="operator">-&gt;</span>m_id<span class="operator"> =</span> blog_1<span class="operator">-&gt;</span>m_id<span class="operator">;</span>
daoError<span class="operator"> =</span> qx<span class="operator">::</span>dao<span class="operator">::</span>fetch_by_id<span class="operator">(</span>blog_isdirty<span class="operator">);</span>
qAssert<span class="operator">(!</span> daoError<span class="operator">.</span>isValid<span class="operator">() &amp;&amp; !</span> blog_isdirty<span class="operator">.</span>isDirty<span class="operator">());</span>
blog_isdirty<span class="operator">-&gt;</span>m_text<span class="operator"> =</span><span class="string"> "blog property 'text' modified =&gt; blog is dirty !!!"</span><span class="operator">;</span>
QStringList lstDiff<span class="operator">;</span><span class="type"> bool</span> bDirty<span class="operator"> =</span> blog_isdirty<span class="operator">.</span>isDirty<span class="operator">(</span>lstDiff<span class="operator">);</span>
qAssert<span class="operator">(</span>bDirty<span class="operator"> &amp;&amp; (</span>lstDiff<span class="operator">.</span>count<span class="operator">() ==</span><span class="int"> 1</span><span class="operator">) &amp;&amp; (</span>lstDiff<span class="operator">.</span>at<span class="operator">(</span><span class="int">0</span><span class="operator">) ==</span><span class="string"> "blog_text"</span><span class="operator">));</span><span class="flow">
if</span><span class="operator"> (</span>bDirty<span class="operator">) {</span> qDebug<span class="operator">(</span><span class="string">"[QxOrm] test dirty 1 : blog is dirty =&gt; '%s'"</span><span class="operator">,</span> qPrintable<span class="operator">(</span>lstDiff<span class="operator">.</span>join<span class="operator">(</span><span class="string">"|"</span><span class="operator">))); }</span><span class="comment">
// Update only property 'm_text' of 'blog_isdirty'
</span> daoError<span class="operator"> =</span> qx<span class="operator">::</span>dao<span class="operator">::</span>update_optimized<span class="operator">(</span>blog_isdirty<span class="operator">);</span>
qAssert<span class="operator">(!</span> daoError<span class="operator">.</span>isValid<span class="operator">() &amp;&amp; !</span> blog_isdirty<span class="operator">.</span>isDirty<span class="operator">());</span>
qx<span class="operator">::</span>dump<span class="operator">(</span>blog_isdirty<span class="operator">);</span><span class="comment">
// Test 'isDirty()' method with a container
</span><span class="keyword"> typedef</span> qx<span class="operator">::</span>dao<span class="operator">::</span>ptr<span class="operator">&lt;</span> QList<span class="operator">&lt;</span>author_ptr<span class="operator">&gt; &gt;</span> type_lst_author_test_is_dirty<span class="operator">;</span>
type_lst_author_test_is_dirty container_isdirty<span class="operator"> =</span> type_lst_author_test_is_dirty<span class="operator">(</span><span class="keyword">new</span> QList<span class="operator">&lt;</span>author_ptr<span class="operator">&gt;());</span>
daoError<span class="operator"> =</span> qx<span class="operator">::</span>dao<span class="operator">::</span>fetch_all<span class="operator">(</span>container_isdirty<span class="operator">);</span>
qAssert<span class="operator">(!</span> daoError<span class="operator">.</span>isValid<span class="operator">() &amp;&amp; !</span> container_isdirty<span class="operator">.</span>isDirty<span class="operator">() &amp;&amp; (</span>container_isdirty<span class="operator">-&gt;</span>count<span class="operator">() ==</span><span class="int"> 3</span><span class="operator">));</span>
author_ptr author_ptr_dirty<span class="operator"> =</span> container_isdirty<span class="operator">-&gt;</span>at<span class="operator">(</span><span class="int">1</span><span class="operator">);</span>
author_ptr_dirty<span class="operator">-&gt;</span>m_name<span class="operator"> =</span><span class="string"> "author name modified at index 1 =&gt; container is dirty !!!"</span><span class="operator">;</span>
bDirty<span class="operator"> =</span> container_isdirty<span class="operator">.</span>isDirty<span class="operator">(</span>lstDiff<span class="operator">);</span>
qAssert<span class="operator">(</span>bDirty<span class="operator"> &amp;&amp; (</span>lstDiff<span class="operator">.</span>count<span class="operator">() ==</span><span class="int"> 1</span><span class="operator">));</span><span class="flow">
if</span><span class="operator"> (</span>bDirty<span class="operator">) {</span> qDebug<span class="operator">(</span><span class="string">"[QxOrm] test dirty 2 : container is dirty =&gt; '%s'"</span><span class="operator">,</span> qPrintable<span class="operator">(</span>lstDiff<span class="operator">.</span>join<span class="operator">(</span><span class="string">"|"</span><span class="operator">))); }</span>
author_ptr_dirty<span class="operator"> =</span> container_isdirty<span class="operator">-&gt;</span>at<span class="operator">(</span><span class="int">2</span><span class="operator">);</span>
author_ptr_dirty<span class="operator">-&gt;</span>m_birthdate<span class="operator"> =</span> QDate<span class="operator">(</span><span class="int">1998</span><span class="operator">,</span><span class="int"> 03</span><span class="operator">,</span><span class="int"> 06</span><span class="operator">);</span>
bDirty<span class="operator"> =</span> container_isdirty<span class="operator">.</span>isDirty<span class="operator">(</span>lstDiff<span class="operator">);</span>
qAssert<span class="operator">(</span>bDirty<span class="operator"> &amp;&amp; (</span>lstDiff<span class="operator">.</span>count<span class="operator">() ==</span><span class="int"> 2</span><span class="operator">));</span><span class="flow">
if</span><span class="operator"> (</span>bDirty<span class="operator">) {</span> qDebug<span class="operator">(</span><span class="string">"[QxOrm] test dirty 3 : container is dirty =&gt; '%s'"</span><span class="operator">,</span> qPrintable<span class="operator">(</span>lstDiff<span class="operator">.</span>join<span class="operator">(</span><span class="string">"|"</span><span class="operator">))); }</span><span class="comment">
// Update only property 'm_name' at position 1, only property 'm_birthdate' at position 2 and nothing at position 0
</span> daoError<span class="operator"> =</span> qx<span class="operator">::</span>dao<span class="operator">::</span>update_optimized<span class="operator">(</span>container_isdirty<span class="operator">);</span>
qAssert<span class="operator">(!</span> daoError<span class="operator">.</span>isValid<span class="operator">() &amp;&amp; !</span> container_isdirty<span class="operator">.</span>isDirty<span class="operator">());</span>
qx<span class="operator">::</span>dump<span class="operator">(</span>container_isdirty<span class="operator">);</span><span class="comment">
// Fetch only property 'm_dt_creation' of blog
</span> QStringList lstColumns<span class="operator"> =</span> QStringList<span class="operator">() &lt;&lt;</span><span class="string"> "date_creation"</span><span class="operator">;</span>
list_blog lst_blog_with_only_date_creation<span class="operator">;</span>
daoError<span class="operator"> =</span> qx<span class="operator">::</span>dao<span class="operator">::</span>fetch_all<span class="operator">(</span>lst_blog_with_only_date_creation<span class="operator">,</span> NULL<span class="operator">,</span> lstColumns<span class="operator">);</span>
qAssert<span class="operator">(!</span> daoError<span class="operator">.</span>isValid<span class="operator">() &amp;&amp; (</span>lst_blog_with_only_date_creation<span class="operator">.</span>size<span class="operator">() &gt;</span><span class="int"> 0</span><span class="operator">));</span><span class="flow">
if</span><span class="operator"> ((</span>lst_blog_with_only_date_creation<span class="operator">.</span>size<span class="operator">() &gt;</span><span class="int"> 0</span><span class="operator">) &amp;&amp; (</span>lst_blog_with_only_date_creation<span class="operator">[</span><span class="int">0</span><span class="operator">] !=</span> NULL<span class="operator">))
{</span> qAssert<span class="operator">(</span>lst_blog_with_only_date_creation<span class="operator">[</span><span class="int">0</span><span class="operator">]-&gt;</span>m_text<span class="operator">.</span>isEmpty<span class="operator">()); }</span>
qx<span class="operator">::</span>dump<span class="operator">(</span>lst_blog_with_only_date_creation<span class="operator">);</span></pre>
</td>
</tr>
</tbody>
</table>
</td>
</tr>
</tbody>
</table>
<br><br>
<a name="faq_90"><u><b>Should I use <i>QString</i> or <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> advises to use the <a href="http://doc.qt.io/qt-5/QString.html"
target="_blank"><i>QString</i></a> class for the management of the character strings.<br>
Even if <b>boost</b> provides many functionalities with its module <a
href="http://www.boost.org/doc/libs/release/doc/html/string_algo.html"
target="_blank"><i>boost::string_algo</i></a>, the <i>QString</i> class is easier to use and
supports many formats : <i>ASCII, Utf8, Utf16...</i><br>
However, <b>QxOrm</b> is compatible with <i>std::string</i> and <i>std::wstring</i> if you prefer to
use this kind of character strings.
</td>
</tr>
</tbody>
</table>
<br><br>
<a name="faq_95"><u><b>Is it necessary to use <i>smart-pointers</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> strongly advises to use <b>boost</b> or <b>Qt</b> <i>smart-pointers</i>.<br>
The C++ language does not have <i>Garbage Collector</i> like <i>Java</i> or <i>C#</i> for example.<br>
The use of <i>smart-pointers</i> simplifies the memory management in C++.<br>
The ideal in a C++ program is not to have any call to <i>delete</i> or <i>delete[]</i>.<br>
Furthermore, <i>smart-pointer</i> is a new functionality of the new C++ standard : <b>C++1x</b>.<br>
It is thus essential to know the following classes today :
<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> and <i>weak_ptr</i></a> for the smart
pointers of <b>boost</b> library
</li>
<li><a href="http://doc-snapshots.qt.io/4.8/qsharedpointer.html"
target="_blank"><i>QSharedPointer</i>, <i>QScopedPointer</i> and <i>QWeakPointer</i></a> for the
smart pointers of <b>Qt</b> library
</li>
</ul>
</td>
</tr>
</tbody>
</table>
<br><br>
<a name="faq_100"><u><b>The primary key is <i>long</i> type by default. Is it possible to use a key of
<i>QString</i> type or other ?</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">
It is possible to define a unique id of <i>QString</i> type or other with <b>QxOrm</b> library.<br>
By default, the unique id is <i>long</i> type.<br>
To indicate that a class has a single identifier of <i>QString</i> type or other, it is necessary to
specialize the template <i>qx::trait::get_primary_key</i>.<br>
To simplify, you can use the macro : <b><i>QX_REGISTER_PRIMARY_KEY(myClass, QString)</i></b>.<br>
<br>
<b>Warning :</b> the macro <b><i>QX_REGISTER_PRIMARY_KEY</i></b> must be used before the macro
<b><i>QX_REGISTER_HPP_...</i></b> in the definition of your class, otherwise a compilation error
occurs.<br>
<br>
Here is an example with <i>author</i> class of <i>qxBlog</i> tutorial and a <i>QString</i> primary key
:<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">
// -- properties
</span> QString m_id<span class="operator">;</span>
QString m_name<span class="operator">;</span><span class="comment">
// -- constructor, virtual destructor
</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>How to define a '<i>multi-columns primary key</i>' (<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> supports '<i>multi-columns primary key</i>'.<br>
The class id must be defined with following type :<br>
* <i>QPair</i> or <i>std::pair</i> to define 2 columns<br>
* <i>boost::tuple</i> to define from 2 columns to 9 columns<br>
<br>
It is necessary to use the macro <b><i>QX_REGISTER_PRIMARY_KEY()</i></b> to specialize the template
and to map class id with multi-columns in database.<br>
The list of multi-columns names must be defined with '<b>|</b>' character :
'<i>column1|column2|column3|etc...</i>'.<br>
<br>
<b>Sample</b> with class '<i>author</i>' from project '<i>qxBlogCompositeKey</i>', this class has an
id mapped to 3 columns in database :<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">
// -- composite key (multi-column primary key in database)
</span><span class="keyword"> typedef</span> boost<span class="operator">::</span>tuple<span class="operator">&lt;</span>QString<span class="operator">,</span><span class="type"> long</span><span class="operator">,</span> QString<span class="operator">&gt;</span> type_composite_key<span class="operator">;</span><span class="keyword">
static</span> QString str_composite_key<span class="operator">() {</span><span class="flow"> return</span><span class="string"> "author_id_0|author_id_1|author_id_2"</span><span class="operator">; }</span><span class="comment">
// -- typedef
</span><span class="keyword"> typedef</span> boost<span class="operator">::</span>shared_ptr<span class="operator">&lt;</span>blog<span class="operator">&gt;</span> blog_ptr<span class="operator">;</span><span class="keyword">
typedef</span> std<span class="operator">::</span>vector<span class="operator">&lt;</span>blog_ptr<span class="operator">&gt;</span> list_blog<span class="operator">;</span><span class="comment">
// -- enum
</span><span class="keyword"> enum</span> enum_sex<span class="operator"> {</span> male<span class="operator">,</span> female<span class="operator">,</span> unknown<span class="operator"> };</span><span class="comment">
// -- properties
</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">
// -- contructor, virtual destructor
</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">
// -- methods
</span><span class="type"> int</span> age<span class="operator">()</span><span class="keyword"> const</span><span class="operator">;</span><span class="comment">
// -- methods "get" to composite key
</span> type_composite_key getId<span class="operator">()</span><span class="keyword"> const</span><span class="operator"> {</span><span class="flow"> return</span> m_id<span class="operator">; }</span>
QString getId_0<span class="operator">()</span><span class="keyword"> const</span><span class="operator"> {</span><span class="flow"> return</span> boost<span class="operator">::</span>tuples<span class="operator">::</span>get<span class="operator">&lt;</span><span class="int">0</span><span class="operator">&gt;(</span>m_id<span class="operator">); }</span><span class="type">
long</span> getId_1<span class="operator">()</span><span class="keyword"> const</span><span class="operator"> {</span><span class="flow"> return</span> boost<span class="operator">::</span>tuples<span class="operator">::</span>get<span class="operator">&lt;</span><span class="int">1</span><span class="operator">&gt;(</span>m_id<span class="operator">); }</span>
QString getId_2<span class="operator">()</span><span class="keyword"> const</span><span class="operator"> {</span><span class="flow"> return</span> boost<span class="operator">::</span>tuples<span class="operator">::</span>get<span class="operator">&lt;</span><span class="int">2</span><span class="operator">&gt;(</span>m_id<span class="operator">); }</span><span class="comment">
// -- methods "set" to composite key
</span><span class="type"> void</span> setId_0<span class="operator">(</span><span class="keyword">const</span> QString<span class="operator"> &amp;</span> s<span class="operator">) {</span> boost<span class="operator">::</span>tuples<span class="operator">::</span>get<span class="operator">&lt;</span><span class="int">0</span><span class="operator">&gt;(</span>m_id<span class="operator">) =</span> s<span class="operator">; }</span><span class="type">
void</span> setId_1<span class="operator">(</span><span class="type">long</span> l<span class="operator">) {</span> boost<span class="operator">::</span>tuples<span class="operator">::</span>get<span class="operator">&lt;</span><span class="int">1</span><span class="operator">&gt;(</span>m_id<span class="operator">) =</span> l<span class="operator">; }</span><span class="type">
void</span> setId_2<span class="operator">(</span><span class="keyword">const</span> QString<span class="operator"> &amp;</span> s<span class="operator">) {</span> boost<span class="operator">::</span>tuples<span class="operator">::</span>get<span class="operator">&lt;</span><span class="int">2</span><span class="operator">&gt;(</span>m_id<span class="operator">) =</span> s<span class="operator">; }
};</span>
QX_REGISTER_PRIMARY_KEY<span class="operator">(</span>author<span class="operator">,</span> author<span class="operator">::</span>type_composite_key<span class="operator">)</span>
QX_REGISTER_HPP_QX_BLOG<span class="operator">(</span>author<span class="operator">,</span> qx<span class="operator">::</span>trait<span class="operator">::</span>no_base_class_defined<span class="operator">,</span><span class="int"> 0</span><span class="operator">)</span><span class="keyword">
typedef</span> boost<span class="operator">::</span>shared_ptr<span class="operator">&lt;</span>author<span class="operator">&gt;</span> author_ptr<span class="operator">;</span><span class="keyword">
typedef</span> qx<span class="operator">::</span>QxCollection<span class="operator">&lt;</span>author<span class="operator">::</span>type_composite_key<span class="operator">,</span> author_ptr<span class="operator">&gt;</span> list_author<span class="operator">;</span><span class="pre">
#endif // _QX_BLOG_AUTHOR_H_
</span></pre>
</td>
</tr>
</tbody>
</table>
<br>
<table border="1" bgcolor="#FFFFFF">
<col>
<tbody>
<tr>
<td>
<pre><span class="pre">#include "../include/precompiled.h"
#include "../include/author.h"
#include "../include/blog.h"
#include &lt;QxOrm_Impl.h&gt;
</span>
QX_REGISTER_CPP_QX_BLOG<span class="operator">(</span>author<span class="operator">)</span><span class="keyword">
namespace</span> qx<span class="operator"> {</span><span class="keyword">
template</span><span class="operator"> &lt;&gt;</span><span class="type"> void</span> register_class<span class="operator">(</span>QxClass<span class="operator">&lt;</span>author<span class="operator">&gt; &amp;</span> t<span class="operator">)
{</span>
t<span class="operator">.</span>id<span class="operator">(&amp;</span> author<span class="operator">::</span>m_id<span class="operator">,</span> author<span class="operator">::</span>str_composite_key<span class="operator">());</span>
t<span class="operator">.</span>data<span class="operator">(&amp;</span> author<span class="operator">::</span>m_name<span class="operator">,</span><span class="string"> "name"</span><span class="operator">);</span>
t<span class="operator">.</span>data<span class="operator">(&amp;</span> author<span class="operator">::</span>m_birthdate<span class="operator">,</span><span class="string"> "birthdate"</span><span class="operator">);</span>
t<span class="operator">.</span>data<span class="operator">(&amp;</span> author<span class="operator">::</span>m_sex<span class="operator">,</span><span class="string"> "sex"</span><span class="operator">);</span>
t<span class="operator">.</span>relationOneToMany<span class="operator">(&amp;</span> author<span class="operator">::</span>m_blogX<span class="operator">,</span> blog<span class="operator">::</span>str_composite_key<span class="operator">(),</span> author<span class="operator">::</span>str_composite_key<span class="operator">());</span>
t<span class="operator">.</span>fct_0<span class="operator">&lt;</span><span class="type">int</span><span class="operator">&gt;(&amp;</span> author<span class="operator">::</span>age<span class="operator">,</span><span class="string"> "age"</span><span class="operator">);
}}</span><span class="type">
int</span> author<span class="operator">::</span>age<span class="operator">()</span><span class="keyword"> const</span><span class="operator">
{</span><span class="flow">
if</span><span class="operator"> (!</span> m_birthdate<span class="operator">.</span>isValid<span class="operator">()) {</span><span class="flow"> return</span><span class="operator"> -</span><span class="int">1</span><span class="operator">; }</span><span class="flow">
return</span><span class="operator"> (</span>QDate<span class="operator">::</span>currentDate<span class="operator">().</span>year<span class="operator">() -</span> m_birthdate<span class="operator">.</span>year<span class="operator">());
}</span>
</pre>
</td>
</tr>
</tbody>
</table>
</td>
</tr>
</tbody>
</table>
<br><br>
<a name="faq_105"><u><b>How to register <i>private</i> or <i>protected</i> members into QxOrm context
?</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">
To register <i>private</i> or <i>protected</i> members into QxOrm context
(<i>qx::register_class&lt;T&gt;</i> function), it's necessary to declare some <i>friend class</i>.<br>
To simplify writing C++ <i>template</i>, QxOrm library provides this macro :
<b>QX_REGISTER_FRIEND_CLASS(myClass)</b>.<br>
An example using this macro can be found in <i>./test/qxDllSample/dll1/</i> directory of QxOrm package
with <i>CPerson</i> class :<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>How to enable/disable the module <i>QxMemLeak</i> for automatic detection of memory
leaks ?</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">
<i>QxMemLeak</i> module provides a fast detection of memory leaks in <i>Debug</i> mode once the
execution of the program is finished (with indication of the file and the line =&gt; style MFC from
Microsoft).<br>
This module is developed by <a href="http://wyw.dcweb.cn/leakage.htm" target="_blank">Wu Yongwei</a>
and has undergone some modifications to be integrated in <b>QxOrm</b>.<br>
If another tool is already used in your projects (<i>Valgrind</i> for example), this functionality
should not be activated.<br>
To enable/disable <i>QxMemLeak</i> module, all is needed is to modify the constant
<b><i>_QX_USE_MEM_LEAK_DETECTION</i></b> defined in the <i>QxConfig.h.</i> file<i>.</i><br>
A recompilation of QxOrm library is necessary to take into account this modification.
</td>
</tr>
</tbody>
</table>
<br><br>
<a name="faq_120"><u><b>How to manage inheritance and database ?</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">
With <i>ORM</i> tools, there is usually 3 strategies to manage inheritance and database :
<ul>
<li><i><a href="http://martinfowler.com/eaaCatalog/singleTableInheritance.html"
target="_blank">Single Table Inheritance</a></i> ;
</li>
<li><i><a href="http://martinfowler.com/eaaCatalog/classTableInheritance.html" target="_blank">Class
Table Inheritance</a></i> ;
</li>
<li><i><a href="http://martinfowler.com/eaaCatalog/concreteTableInheritance.html"
target="_blank">Concrete Table Inheritance</a></i>.
</li>
</ul>
<b>QxOrm</b> works by default with <i>Concrete Table Inheritance</i> strategy (others are not
supported yet).<br>
Many tutorials and forums are available on internet to more details about <i>ORM</i> inheritance and
database.<br>
You can find a sample in the directory <i>./test/qxDllSample/dll2/</i> with the class
<i>BaseClassTrigger</i>.
</td>
</tr>
</tbody>
</table>
<br><br>
<a name="faq_130"><u><b>How to define a '<i>Trigger</i>' with 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">
With <b>QxOrm</b> <i>Trigger</i>, it is possible to execute process before and/or after an insert,
update or delete query in the database.<br>
You can find a sample in the directory <i>./test/qxDllSample/dll2/</i> with the class
<i>BaseClassTrigger</i>.<br>
The class <i>BaseClassTrigger</i> contains 5 properties : <i>m_id</i>, <i>m_dateCreation</i>,
<i>m_dateModification</i>, <i>m_userCreation</i> and <i>m_userModification</i>.<br>
Each property will be automatically auto-updated for all derived classes from <i>BaseClassTrigger</i>
(see <i>Foo</i> class and <i>Bar</i> class in the same project).<br>
It is necessary to specialize '<i>QxDao_Trigger</i>' template to work with this feature.<br>
<br>
<table border="1" bgcolor="#FFFFFF">
<col>
<tbody>
<tr>
<td>
<pre><span class="pre">#ifndef _QX_BASE_CLASS_TRIGGER_H_
#define _QX_BASE_CLASS_TRIGGER_H_
</span><span class="keyword">
class</span> QX_DLL2_EXPORT BaseClassTrigger<span class="operator">
{</span>
QX_REGISTER_FRIEND_CLASS<span class="operator">(</span>BaseClassTrigger<span class="operator">)</span><span class="keyword">
protected</span><span class="operator">:</span><span class="type">
long</span> m_id<span class="operator">;</span>
QDateTime m_dateCreation<span class="operator">;</span>
QDateTime m_dateModification<span class="operator">;</span>
QString m_userCreation<span class="operator">;</span>
QString m_userModification<span class="operator">;</span><span class="keyword">
public</span><span class="operator">:</span>
BaseClassTrigger<span class="operator">() :</span> m_id<span class="operator">(</span><span class="int">0</span><span class="operator">) { ; }</span><span class="keyword">
virtual</span><span class="operator"> ~</span>BaseClassTrigger<span class="operator">() { ; }</span><span class="type">
long</span> getId<span class="operator">()</span><span class="keyword"> const</span><span class="operator"> {</span><span class="flow"> return</span> m_id<span class="operator">; }</span>
QDateTime getDateCreation<span class="operator">()</span><span class="keyword"> const</span><span class="operator"> {</span><span class="flow"> return</span> m_dateCreation<span class="operator">; }</span>
QDateTime getDateModification<span class="operator">()</span><span class="keyword"> const</span><span class="operator"> {</span><span class="flow"> return</span> m_dateModification<span class="operator">; }</span>
QString getUserCreation<span class="operator">()</span><span class="keyword"> const</span><span class="operator"> {</span><span class="flow"> return</span> m_userCreation<span class="operator">; }</span>
QString getUserModification<span class="operator">()</span><span class="keyword"> const</span><span class="operator"> {</span><span class="flow"> return</span> m_userModification<span class="operator">; }</span><span class="type">
void</span> setId<span class="operator">(</span><span class="type">long</span> l<span class="operator">) {</span> m_id<span class="operator"> =</span> l<span class="operator">; }</span><span class="type">
void</span> setDateCreation<span class="operator">(</span><span class="keyword">const</span> QDateTime<span class="operator"> &amp;</span> dt<span class="operator">) {</span> m_dateCreation<span class="operator"> =</span> dt<span class="operator">; }</span><span class="type">
void</span> setDateModification<span class="operator">(</span><span class="keyword">const</span> QDateTime<span class="operator"> &amp;</span> dt<span class="operator">) {</span> m_dateModification<span class="operator"> =</span> dt<span class="operator">; }</span><span class="type">
void</span> setUserCreation<span class="operator">(</span><span class="keyword">const</span> QString<span class="operator"> &amp;</span> s<span class="operator">) {</span> m_userCreation<span class="operator"> =</span> s<span class="operator">; }</span><span class="type">
void</span> setUserModification<span class="operator">(</span><span class="keyword">const</span> QString<span class="operator"> &amp;</span> s<span class="operator">) {</span> m_userModification<span class="operator"> =</span> s<span class="operator">; }</span><span class="type">
void</span> onBeforeInsert<span class="operator">(</span>qx<span class="operator">::</span>dao<span class="operator">::</span>detail<span class="operator">::</span>IxDao_Helper<span class="operator"> *</span> dao<span class="operator">);</span><span class="type">
void</span> onBeforeUpdate<span class="operator">(</span>qx<span class="operator">::</span>dao<span class="operator">::</span>detail<span class="operator">::</span>IxDao_Helper<span class="operator"> *</span> dao<span class="operator">);
};</span>
QX_REGISTER_HPP_QX_DLL2<span class="operator">(</span>BaseClassTrigger<span class="operator">,</span> qx<span class="operator">::</span>trait<span class="operator">::</span>no_base_class_defined<span class="operator">,</span><span class="int"> 0</span><span class="operator">)</span><span class="keyword">
namespace</span> qx<span class="operator"> {</span><span class="keyword">
namespace</span> dao<span class="operator"> {</span><span class="keyword">
namespace</span> detail<span class="operator"> {</span><span class="keyword">
template</span><span class="operator"> &lt;&gt;</span><span class="keyword">
struct</span> QxDao_Trigger<span class="operator">&lt;</span>BaseClassTrigger<span class="operator">&gt;
{</span><span class="keyword">
static inline</span><span class="type"> void</span> onBeforeInsert<span class="operator">(</span>BaseClassTrigger<span class="operator"> *</span> t<span class="operator">,</span> qx<span class="operator">::</span>dao<span class="operator">::</span>detail<span class="operator">::</span>IxDao_Helper<span class="operator"> *</span> dao<span class="operator">)
{</span><span class="flow"> if</span><span class="operator"> (</span>t<span class="operator">) {</span> t<span class="operator">-&gt;</span>onBeforeInsert<span class="operator">(</span>dao<span class="operator">); } }</span><span class="keyword">
static inline</span><span class="type"> void</span> onBeforeUpdate<span class="operator">(</span>BaseClassTrigger<span class="operator"> *</span> t<span class="operator">,</span> qx<span class="operator">::</span>dao<span class="operator">::</span>detail<span class="operator">::</span>IxDao_Helper<span class="operator"> *</span> dao<span class="operator">)
{</span><span class="flow"> if</span><span class="operator"> (</span>t<span class="operator">) {</span> t<span class="operator">-&gt;</span>onBeforeUpdate<span class="operator">(</span>dao<span class="operator">); } }</span><span class="keyword">
static inline</span><span class="type"> void</span> onBeforeDelete<span class="operator">(</span>BaseClassTrigger<span class="operator"> *</span> t<span class="operator">,</span> qx<span class="operator">::</span>dao<span class="operator">::</span>detail<span class="operator">::</span>IxDao_Helper<span class="operator"> *</span> dao<span class="operator">)
{</span> Q_UNUSED<span class="operator">(</span>t<span class="operator">);</span> Q_UNUSED<span class="operator">(</span>dao<span class="operator">); }</span><span class="keyword">
static inline</span><span class="type"> void</span> onBeforeFetch<span class="operator">(</span>BaseClassTrigger<span class="operator"> *</span> t<span class="operator">,</span> qx<span class="operator">::</span>dao<span class="operator">::</span>detail<span class="operator">::</span>IxDao_Helper<span class="operator"> *</span> dao<span class="operator">)
{</span> Q_UNUSED<span class="operator">(</span>t<span class="operator">);</span> Q_UNUSED<span class="operator">(</span>dao<span class="operator">); }</span><span class="keyword">
static inline</span><span class="type"> void</span> onAfterInsert<span class="operator">(</span>BaseClassTrigger<span class="operator"> *</span> t<span class="operator">,</span> qx<span class="operator">::</span>dao<span class="operator">::</span>detail<span class="operator">::</span>IxDao_Helper<span class="operator"> *</span> dao<span class="operator">)
{</span> Q_UNUSED<span class="operator">(</span>t<span class="operator">);</span> Q_UNUSED<span class="operator">(</span>dao<span class="operator">); }</span><span class="keyword">
static inline</span><span class="type"> void</span> onAfterUpdate<span class="operator">(</span>BaseClassTrigger<span class="operator"> *</span> t<span class="operator">,</span> qx<span class="operator">::</span>dao<span class="operator">::</span>detail<span class="operator">::</span>IxDao_Helper<span class="operator"> *</span> dao<span class="operator">)
{</span> Q_UNUSED<span class="operator">(</span>t<span class="operator">);</span> Q_UNUSED<span class="operator">(</span>dao<span class="operator">); }</span><span class="keyword">
static inline</span><span class="type"> void</span> onAfterDelete<span class="operator">(</span>BaseClassTrigger<span class="operator"> *</span> t<span class="operator">,</span> qx<span class="operator">::</span>dao<span class="operator">::</span>detail<span class="operator">::</span>IxDao_Helper<span class="operator"> *</span> dao<span class="operator">)
{</span> Q_UNUSED<span class="operator">(</span>t<span class="operator">);</span> Q_UNUSED<span class="operator">(</span>dao<span class="operator">); }
static inline</span><span class="type"> void</span> onAfterFetch<span class="operator">(</span>BaseClassTrigger<span class="operator"> *</span> t<span class="operator">,</span> qx<span class="operator">::</span>dao<span class="operator">::</span>detail<span class="operator">::</span>IxDao_Helper<span class="operator"> *</span> dao<span class="operator">)
{</span> Q_UNUSED<span class="operator">(</span>t<span class="operator">);</span> Q_UNUSED<span class="operator">(</span>dao<span class="operator">); }
};
}</span><span class="comment"> // namespace detail
</span><span class="operator">}</span><span class="comment"> // namespace dao
</span><span class="operator">}</span><span class="comment"> // namespace qx
</span><span class="pre">
#endif // _QX_BASE_CLASS_TRIGGER_H_
</span></pre>
</td>
</tr>
</tbody>
</table>
<br>
<table border="1" bgcolor="#FFFFFF">
<col>
<tbody>
<tr>
<td>
<pre><span class="pre">#include "../include/precompiled.h"
#include "../include/BaseClassTrigger.h"
#include &lt;QxOrm_Impl.h&gt;
</span>
QX_REGISTER_CPP_QX_DLL2<span class="operator">(</span>BaseClassTrigger<span class="operator">)</span><span class="keyword">
namespace</span> qx<span class="operator"> {</span><span class="keyword">
template</span><span class="operator"> &lt;&gt;</span><span class="type"> void</span> register_class<span class="operator">(</span>QxClass<span class="operator">&lt;</span>BaseClassTrigger<span class="operator">&gt; &amp;</span> t<span class="operator">)
{</span>
IxDataMember<span class="operator"> *</span> pData<span class="operator"> =</span> NULL<span class="operator">;</span>
pData<span class="operator"> =</span> t<span class="operator">.</span>id<span class="operator">(&amp;</span> BaseClassTrigger<span class="operator">::</span>m_id<span class="operator">,</span><span class="string"> "id"</span><span class="operator">);</span>
pData<span class="operator"> =</span> t<span class="operator">.</span>data<span class="operator">(&amp;</span> BaseClassTrigger<span class="operator">::</span>m_dateCreation<span class="operator">,</span><span class="string"> "date_creation"</span><span class="operator">);</span>
pData<span class="operator"> =</span> t<span class="operator">.</span>data<span class="operator">(&amp;</span> BaseClassTrigger<span class="operator">::</span>m_dateModification<span class="operator">,</span><span class="string"> "date_modification"</span><span class="operator">);</span>
pData<span class="operator"> =</span> t<span class="operator">.</span>data<span class="operator">(&amp;</span> BaseClassTrigger<span class="operator">::</span>m_userCreation<span class="operator">,</span><span class="string"> "user_creation"</span><span class="operator">);</span>
pData<span class="operator"> =</span> t<span class="operator">.</span>data<span class="operator">(&amp;</span> BaseClassTrigger<span class="operator">::</span>m_userModification<span class="operator">,</span><span class="string"> "user_modification"</span><span class="operator">);
}}</span><span class="type">
void</span> BaseClassTrigger<span class="operator">::</span>onBeforeInsert<span class="operator">(</span>qx<span class="operator">::</span>dao<span class="operator">::</span>detail<span class="operator">::</span>IxDao_Helper<span class="operator"> *</span> dao<span class="operator">)
{</span>
Q_UNUSED<span class="operator">(</span>dao<span class="operator">);</span>
m_dateCreation<span class="operator"> =</span> QDateTime<span class="operator">::</span>currentDateTime<span class="operator">();</span>
m_dateModification<span class="operator"> =</span> QDateTime<span class="operator">::</span>currentDateTime<span class="operator">();</span>
m_userCreation<span class="operator"> =</span><span class="string"> "current_user_1"</span><span class="operator">;</span>
m_userModification<span class="operator"> =</span><span class="string"> "current_user_1"</span><span class="operator">;
}</span><span class="type">
void</span> BaseClassTrigger<span class="operator">::</span>onBeforeUpdate<span class="operator">(</span>qx<span class="operator">::</span>dao<span class="operator">::</span>detail<span class="operator">::</span>IxDao_Helper<span class="operator"> *</span> dao<span class="operator">)
{</span>
Q_UNUSED<span class="operator">(</span>dao<span class="operator">);</span>
m_dateModification<span class="operator"> =</span> QDateTime<span class="operator">::</span>currentDateTime<span class="operator">();</span>
m_userModification<span class="operator"> =</span><span class="string"> "current_user_2"</span><span class="operator">;
}</span>
</pre>
</td>
</tr>
</tbody>
</table>
</td>
</tr>
</tbody>
</table>
<br><br>
<a name="faq_140"><u><b>How to register an abstract class into QxOrm context ?</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 C++ abstract class (with at least one pure virtual method) cannot be mapped to a table of a database
(because it cannot be instantiated).<br>
However, in some case, it can be interesting to define properties into abstract class used by a
persistent object (by inheritance).<br>
A sample of abstract class registered in QxOrm context is available in the directory
<i>./test/qxDllSample/dll2/</i> of QxOrm package with the class <i>BaseClassTrigger</i>.<br>
To register an abstract class into QxOrm context, you have to :
<ul>
<li>register the class with '<i>void register_class</i>' like any other class ;
</li>
<li>use macro <b>QX_REGISTER_ABSTRACT_CLASS(className)</b> just after the class definition.
</li>
</ul>
</td>
</tr>
</tbody>
</table>
<br><br>
<a name="faq_150"><u><b>How to register a class defined into a namespace into QxOrm context
?</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">
If a class is defined into a namespace, a compilation error occurs using macros :
<b>QX_REGISTER_HPP</b> and <b>QX_REGISTER_CPP</b>.<br>
To avoid this compilation error, it is necessary to use followings macros :
<b>QX_REGISTER_COMPLEX_CLASS_NAME_HPP</b> and <b>QX_REGISTER_COMPLEX_CLASS_NAME_CPP</b>.<br>
You can find a sample in the directory <i>./test/qxDllSample/dll1/</i> of QxOrm package with the class
<i>CPerson</i> defined into namespace <i>qx::test</i> :<br>
<br>
* <i><b>QX_REGISTER_COMPLEX_CLASS_NAME_HPP_QX_DLL1(qx::test::CPerson, QObject, 0,
qx_test_CPerson)</b></i>
</td>
</tr>
</tbody>
</table>
<br><br>
<a name="faq_160"><u><b>How to define a soft delete behavior ?</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 soft delete doesn't remove rows from database (this is not a physical delete) : a new column is
added to the table definition to flag a row as deleted or not.<br>
This column can contain a boolean (1 means row deleted, 0 or NULL means row not deleted), or can
contain deletion date-time (if empty or NULL, row is not deleted).<br>
So you can reactivate a deleted row by setting NULL or empty value into database.<br>
<br>
To define a soft delete behavior with QxOrm library, you have to use the class <b>qx::QxSoftDelete</b>
in function mapping by class <i>qx::register_class&lt;T&gt;</i>.<br>
Here is an example with the class <i>Bar</i> containing 2 properties <i>m_id</i> and <i>m_desc</i>
:<br>
<br>
<table border="1" bgcolor="#FFFFFF">
<col>
<tbody>
<tr>
<td>
<pre><span class="keyword">namespace</span> qx<span class="operator"> {</span><span class="keyword">
template</span><span class="operator"> &lt;&gt;</span><span class="type"> void</span> register_class<span class="operator">(</span>QxClass<span class="operator">&lt;</span>Bar<span class="operator">&gt; &amp;</span> t<span class="operator">)
{</span>
t<span class="operator">.</span>setSoftDelete<span class="operator">(</span>qx<span class="operator">::</span>QxSoftDelete<span class="operator">(</span><span class="string">"deleted_at"</span><span class="operator">));</span>
t<span class="operator">.</span>id<span class="operator">(&amp;</span> Bar<span class="operator">::</span>m_id<span class="operator">,</span><span class="string"> "id"</span><span class="operator">);</span>
t<span class="operator">.</span>data<span class="operator">(&amp;</span> Bar<span class="operator">::</span>m_desc<span class="operator">,</span><span class="string"> "desc"</span><span class="operator">);
}}</span></pre>
</td>
</tr>
</tbody>
</table>
<br>
SQL queries builded by QxOrm library will take into account this soft delete parameter to add
conditions (don't fetch deleted item, don't delete physically a row, etc.).<br>
For example, if you execute this code with the class <i>Bar</i> :<br>
<br>
<table border="1" bgcolor="#FFFFFF">
<col>
<tbody>
<tr>
<td>
<pre>Bar_ptr pBar<span class="operator">;</span> pBar<span class="operator">.</span>reset<span class="operator">(</span><span class="keyword">new</span> Bar<span class="operator">());</span>
pBar<span class="operator">-&gt;</span>setId<span class="operator">(</span><span class="int">5</span><span class="operator">);</span>
QSqlError daoError<span class="operator"> =</span> qx<span class="operator">::</span>dao<span class="operator">::</span>delete_by_id<span class="operator">(</span>pBar<span class="operator">);</span> qAssert<span class="operator">(!</span> daoError<span class="operator">.</span>isValid<span class="operator">());</span>
qx_bool bDaoExist<span class="operator"> =</span> qx<span class="operator">::</span>dao<span class="operator">::</span>exist<span class="operator">(</span>pBar<span class="operator">);</span> qAssert<span class="operator">(!</span> bDaoExist<span class="operator">);</span>
daoError<span class="operator"> =</span> qx<span class="operator">::</span>dao<span class="operator">::</span>delete_all<span class="operator">&lt;</span>Bar<span class="operator">&gt;();</span> qAssert<span class="operator">(!</span> daoError<span class="operator">.</span>isValid<span class="operator">());</span><span class="type">
long</span> lBarCount<span class="operator"> =</span> qx<span class="operator">::</span>dao<span class="operator">::</span>count<span class="operator">&lt;</span>Bar<span class="operator">&gt;();</span> qAssert<span class="operator">(</span>lBarCount<span class="operator"> ==</span><span class="int"> 0</span><span class="operator">);</span>
daoError<span class="operator"> =</span> qx<span class="operator">::</span>dao<span class="operator">::</span>destroy_all<span class="operator">&lt;</span>Bar<span class="operator">&gt;();</span> qAssert<span class="operator">(!</span> daoError<span class="operator">.</span>isValid<span class="operator">());</span></pre>
</td>
</tr>
</tbody>
</table>
<br>
You will obtain following output trace :<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>Note :</b> to delete physically a row from database, you have to use followings functions :
<i>qx::dao::destroy_by_id()</i> and <i>qx::dao::destroy_all()</i>.<br>
<br>
<b>Other note :</b> it is recommended to define into database an index on column <i>deleted_at</i> to
optimize execution of SQL queries.<br>
</td>
</tr>
</tbody>
</table>
<br><br>
<a name="faq_170"><u><b>How to use a session (<i>qx::QxSession</i> class) to manage automatically database
transactions (using 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">
A database <a href="http://en.wikipedia.org/wiki/Database_transaction"
target="_blank"><b>transaction</b></a> is a sequence of operations performed as a single logical
unit of work.<br>
If no errors occurred during the execution of the transaction then the system <b>commits</b> the
transaction.<br>
If an error occurs during the transaction, or if the user specifies a <b>rollback</b> operation, the
data manipulations within the transaction are not persisted to the database.<br>
<br>
The <b><a href="../doxygen/html/classqx_1_1_qx_session.html" target="_blank">qx::QxSession</a></b>
class of QxOrm library is designed to manage automatically database transactions (using <a
href="http://en.wikipedia.org/wiki/Resource_Acquisition_Is_Initialization" target="_blank">C++
RAII</a>) :<br>
<br>
<table border="1" bgcolor="#FFFFFF">
<col>
<tbody>
<tr>
<td>
<pre><span class="operator">{</span><span class="comment"> // Start a scope where a new session is instantiated
// Create a session : a valid database connexion by thread is automatically assigned to the session and a transaction is opened
</span>qx<span class="operator">::</span>QxSession session<span class="operator">;</span><span class="comment">
// Execute some operations with database (using += operator of qx::QxSession class and session database connexion)
</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">
// If the session is not valid (so an error occured) =&gt; display first error
</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"> // End of scope : session is destroyed (transaction =&gt; automatically commit or rollback if there is an error)</span></pre>
</td>
</tr>
</tbody>
</table>
<br>
<b>Note :</b> a session can throw a <i>qx::dao::sql_error</i> exception when a SQL error occured (by
default, there is no exception). You can setup this feature using :<br>
* <i>qx::QxSession</i> constructor (for a specific session) ;<br>
* <i>qx::QxSqlDatabase::getSingleton()->setSessionThrowable(bool b)</i> parameter (for all
sessions).<br>
<br>
<b>Other note :</b> don't forget to pass the session database connexion to each <i>qx::dao::xxx</i>
functions (using <i>session.database()</i> method).<br>
Moreover, you can manage your own database connexion (from a connexion pool for example) using
constructor of <i>qx::QxSession</i> class.<br>
<br>
<i>qx::QxSession</i> class provides also persistent methods (CRUD) to make easier to write C++
code.<br>
Here is the same example using methods of <i>qx::QxSession</i> class instead of functions into
<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"> // Start a scope where a new session is instantiated
// Create a session : a valid database connexion by thread is automatically assigned to the session and a transaction is opened
</span> qx<span class="operator">::</span>QxSession session<span class="operator">;</span><span class="comment">
// Execute some operations with database
</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">
// If the session is not valid (so an error occured) =&gt; display first error
</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"> // End of scope : session is destroyed (transaction =&gt; automatically commit or rollback if there is an error)</span></pre>
</td>
</tr>
</tbody>
</table>
<br>
</td>
</tr>
</tbody>
</table>
<br><br>
<a name="faq_180"><u><b>How to persist a type without its source code (class from an external library for
example) ?</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">
QxOrm library can persist every types, not only classes registered in QxOrm context using
<i>qx::register_class&lt;T&gt;()</i>.<br>
<br>
It's necessary to write serialization functions from boost framework, using the <b>non intrusive</b>
method (because source code is not available or is read-only).
For more details on boost serialization module, <a
href="http://www.boost.org/doc/libs/release/libs/serialization/doc/index.html" target="_blank">goto
official website</a>.<br>
<br>
For example, imagine that you have the class '<i>ExtObject3D</i>' from an external library and the
source code is not available or is read-only.
Here is the code to can persist an instance of '<i>ExtObject3D</i>' type into database :<br>
<br>
<table border="1" bgcolor="#FFFFFF">
<col>
<tbody>
<tr>
<td>
<pre><span class="pre">#ifndef _PERSIST_EXTOBJECT3D_H_
#define _PERSIST_EXTOBJECT3D_H_
#include "ExtObject3D.h"
#include &lt;boost/serialization/serialization.hpp&gt;
#include &lt;boost/serialization/split_free.hpp&gt;
#include &lt;boost/serialization/nvp.hpp&gt;
</span><span class="keyword">
namespace</span> boost<span class="operator"> {</span><span class="keyword">
namespace</span> serialization<span class="operator"> {</span><span class="keyword">
template</span><span class="operator"> &lt;</span><span class="keyword">class</span> Archive<span class="operator">&gt;</span><span class="type">
void</span> save<span class="operator">(</span>Archive<span class="operator"> &amp;</span> ar<span class="operator">,</span><span class="keyword"> const</span> ExtObject3D<span class="operator"> &amp;</span> t<span class="operator">,</span><span class="type"> unsigned int</span> version<span class="operator">)
{</span>
Q_UNUSED<span class="operator">(</span>version<span class="operator">);</span><span class="type">
double</span> x<span class="operator">(</span>t<span class="operator">.</span>getX<span class="operator">()),</span> y<span class="operator">(</span>t<span class="operator">.</span>getY<span class="operator">()),</span> z<span class="operator">(</span>t<span class="operator">.</span>getZ<span class="operator">()),</span> angle<span class="operator">(</span>t<span class="operator">.</span>getAngle<span class="operator">());</span>
ar<span class="operator"> &lt;&lt;</span> boost<span class="operator">::</span>serialization<span class="operator">::</span>make_nvp<span class="operator">(</span><span class="string">"x"</span><span class="operator">,</span> x<span class="operator">);</span>
ar<span class="operator"> &lt;&lt;</span> boost<span class="operator">::</span>serialization<span class="operator">::</span>make_nvp<span class="operator">(</span><span class="string">"y"</span><span class="operator">,</span> y<span class="operator">);</span>
ar<span class="operator"> &lt;&lt;</span> boost<span class="operator">::</span>serialization<span class="operator">::</span>make_nvp<span class="operator">(</span><span class="string">"z"</span><span class="operator">,</span> z<span class="operator">);</span>
ar<span class="operator"> &lt;&lt;</span> boost<span class="operator">::</span>serialization<span class="operator">::</span>make_nvp<span class="operator">(</span><span class="string">"angle"</span><span class="operator">,</span> angle<span class="operator">);
}</span><span class="keyword">
template</span><span class="operator"> &lt;</span><span class="keyword">class</span> Archive<span class="operator">&gt;</span><span class="type">
void</span> load<span class="operator">(</span>Archive<span class="operator"> &amp;</span> ar<span class="operator">,</span> ExtObject3D<span class="operator"> &amp;</span> t<span class="operator">,</span><span class="type"> unsigned int</span> version<span class="operator">)
{</span>
Q_UNUSED<span class="operator">(</span>version<span class="operator">);</span><span class="type">
double</span> x<span class="operator">(</span><span class="float">0.0</span><span class="operator">),</span> y<span class="operator">(</span><span class="float">0.0</span><span class="operator">),</span> z<span class="operator">(</span><span class="float">0.0</span><span class="operator">),</span> angle<span class="operator">(</span><span class="float">0.0</span><span class="operator">);</span>
ar<span class="operator"> &gt;&gt;</span> boost<span class="operator">::</span>serialization<span class="operator">::</span>make_nvp<span class="operator">(</span><span class="string">"x"</span><span class="operator">,</span> x<span class="operator">);</span>
ar<span class="operator"> &gt;&gt;</span> boost<span class="operator">::</span>serialization<span class="operator">::</span>make_nvp<span class="operator">(</span><span class="string">"y"</span><span class="operator">,</span> y<span class="operator">);</span>
ar<span class="operator"> &gt;&gt;</span> boost<span class="operator">::</span>serialization<span class="operator">::</span>make_nvp<span class="operator">(</span><span class="string">"z"</span><span class="operator">,</span> z<span class="operator">);</span>
ar<span class="operator"> &gt;&gt;</span> boost<span class="operator">::</span>serialization<span class="operator">::</span>make_nvp<span class="operator">(</span><span class="string">"angle"</span><span class="operator">,</span> angle<span class="operator">);</span>
t<span class="operator">.</span>setX<span class="operator">(</span>x<span class="operator">);</span>
t<span class="operator">.</span>setY<span class="operator">(</span>y<span class="operator">);</span>
t<span class="operator">.</span>setZ<span class="operator">(</span>z<span class="operator">);</span>
t<span class="operator">.</span>setAngle<span class="operator">(</span>angle<span class="operator">);
}
}</span><span class="comment"> // namespace serialization
</span><span class="operator">}</span><span class="comment"> // namespace boost
</span>
BOOST_SERIALIZATION_SPLIT_FREE<span class="operator">(</span>ExtObject3D<span class="operator">)</span><span class="pre">
#endif // _PERSIST_EXTOBJECT3D_H_</span></pre>
</td>
</tr>
</tbody>
</table>
<br>
Now you can persist an instance of '<i>ExtObject3D</i>' type into database : so you can have a
'<i>ExtObject3D</i>' property in a persistent class registered in QxOrm context.
This property can be mapped with a column of type <i>TEXT</i> or <i>VARCHAR</i> into database.<br>
<br>
The default behaviour of QxOrm library is : the instance is serialized to XML format before to be
inserted or updated into database.
This default behaviour can be useful, for example if you want to save a collection of items without to
make relation (so you don't have to manage another table into database).
For example, with a property of type <i>std::vector&lt;mon_objet&gt;</i> in a persistent class without
relation, the list of items will be saved into database under XML format.<br>
<br>
<b>Note :</b> the default behaviour can be easily modified for a specific type.
<i>QtSql</i> engine uses <i>QVariant</i> type to link C++ code and database.
<i>QVariant</i> type can contain text, numeric, binary, etc.
So it can be interesting to specialize the default behaviour (XML serialization) if you want to save
datas under binary format or to optimize your application (XML serialization is not very fast).
You just have to write (with boost serialization functions) a conversion into/from <i>QVariant</i>
type, for example with '<i>ExtObject3D</i>' class :<br>
<br>
<table border="1" bgcolor="#FFFFFF">
<col>
<tbody>
<tr>
<td>
<pre><span class="keyword">namespace</span> qx<span class="operator"> {</span><span class="keyword">
namespace</span> cvt<span class="operator"> {</span><span class="keyword">
namespace</span> detail<span class="operator"> {</span><span class="keyword">
template</span><span class="operator"> &lt;&gt;</span><span class="keyword"> struct</span> QxConvert_ToVariant<span class="operator">&lt;</span> ExtObject3D<span class="operator"> &gt; {</span><span class="keyword">
static inline</span> QVariant toVariant<span class="operator">(</span><span class="keyword">const</span> ExtObject3D<span class="operator"> &amp;</span> t<span class="operator">,</span><span class="keyword"> const</span> QString<span class="operator"> &amp;</span> format<span class="operator">,</span><span class="type"> int</span> index<span class="operator">)
{</span><span class="comment"> /* Ici je convertis ExtObject3D en QVariant */</span><span class="operator"> } };</span><span class="keyword">
template</span><span class="operator"> &lt;&gt;</span><span class="keyword"> struct</span> QxConvert_FromVariant<span class="operator">&lt;</span> ExtObject3D<span class="operator"> &gt; {</span><span class="keyword">
static inline</span> qx_bool fromVariant<span class="operator">(</span><span class="keyword">const</span> QVariant<span class="operator"> &amp;</span> v<span class="operator">,</span> ExtObject3D<span class="operator"> &amp;</span> t<span class="operator">,</span><span class="keyword"> const</span> QString<span class="operator"> &amp;</span> format<span class="operator">,</span><span class="type"> int</span> index<span class="operator">)
{</span><span class="comment"> /* Ici je convertis QVariant en ExtObject3D */</span><span class="operator">;</span><span class="flow"> return</span> qx_bool<span class="operator">(</span><span class="bool">true</span><span class="operator">); } };
}</span><span class="comment"> // namespace detail
</span><span class="operator">}</span><span class="comment"> // namespace cvt
</span><span class="operator">}</span><span class="comment"> // namespace qx</span></pre>
</td>
</tr>
</tbody>
</table>
<br>
</td>
</tr>
</tbody>
</table>
<br><br>
<a name="faq_190"><u><b>How to use introspection engine (or reflection engine) of QxOrm library
?</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">
All classes registered in QxOrm context using <i>qx::register_class&lt;T&gt;()</i> function can be
used by introspection engine (or reflection engine) of QxOrm library.
Introspection engine can provide dynamically (so during program execution) some informations about
types.
Those informations are called <i>meta-datas</i> and can list all classes characteristics (properties,
methods, etc.).
Many programming languages (for example Java or C#) have natively this mechanism, but not C++, that's
why QxOrm library emulates an introspection engine.<br>
<br>
Here is a list of QxOrm library classes to access to <i>meta-datas</i> :
<ul>
<li><a href="../doxygen/html/classqx_1_1_qx_class_x.html" target="_blank">qx::QxClassX</a> :
singleton class to iterate over all classes registered in QxOrm context using
<i>qx::register_class&lt;T&gt;()</i> ;
</li>
<li><a href="../doxygen/html/classqx_1_1_ix_class.html" target="_blank">qx::IxClass</a> : interface
for a class registered in QxOrm context ;</li>
<li><a href="../doxygen/html/classqx_1_1_ix_data_member_x.html"
target="_blank">qx::IxDataMemberX</a> : list of properties associated to a class ;</li>
<li><a href="../doxygen/html/classqx_1_1_ix_data_member.html" target="_blank">qx::IxDataMember</a> :
interface for a class property ;</li>
<li><a href="../doxygen/html/classqx_1_1_ix_function.html" target="_blank">qx::IxFunctionX</a> :
list of methods associated to a class ;</li>
<li><a href="../doxygen/html/classqx_1_1_ix_function.html" target="_blank">qx::IxFunction</a> :
interface for a class method.</li>
</ul>
An instance of <i>qx::IxClass</i> type contains the list of class properties
(<i>qx::IxDataMemberX</i>) and the list of class methods (<i>qx::IxFunctionX</i>).<br>
<br>
Introspection engine of QxOrm library provides :
<ul>
<li>to create dynamically an instance of a class using class name under string format
(<i>qx::create()</i>) ;</li>
<li>to access/modify dynamically the value of an object field (<i>qx::IxDataMember::getValue()</i>
and <i>qx::IxDataMember::setValue()</i>) ;</li>
<li>to invoke dynamically a class method (<i>qx::IxFunction::invoke()</i>) ;</li>
<li>to access to the class hierarchy (<i>qx::IxClass::getBaseClass()</i>).</li>
</ul>
<b>Note :</b> <a href="../doxygen/html/group___qx_service.html" target="_blank">QxService</a> module
of QxOrm library (<a href="./tutorial_2.html" target="_blank">click here to go to the tutorial</a>) to
create easily a C++ application server is based on introspection engine to call dynamically services
methods (client request) on server side.<br>
<br>
Here is a sample using introspection engine : how to dump all classes, properties and methods
registered in QxOrm context ?<br>
<br>
<table border="1" bgcolor="#FFFFFF">
<col>
<tbody>
<tr>
<td>
<pre>QString QxClassX<span class="operator">::</span>dumpAllClasses<span class="operator">()
{</span>
QxClassX<span class="operator">::</span>registerAllClasses<span class="operator">();</span>
QxCollection<span class="operator">&lt;</span>QString<span class="operator">,</span> IxClass<span class="operator"> *&gt; *</span> pAllClasses<span class="operator"> =</span> QxClassX<span class="operator">::</span>getAllClasses<span class="operator">();</span><span class="flow">
if</span><span class="operator"> (!</span> pAllClasses<span class="operator">) {</span> qAssert<span class="operator">(</span><span class="bool">false</span><span class="operator">);</span><span class="flow"> return</span><span class="string"> ""</span><span class="operator">; }</span>
QString sDump<span class="operator">;</span><span class="type">
long</span> lCount<span class="operator"> =</span> pAllClasses<span class="operator">-&gt;</span>count<span class="operator">();</span>
qDebug<span class="operator">(</span><span class="string">"[QxOrm] start dump all registered classes (%ld)"</span><span class="operator">,</span> lCount<span class="operator">);</span>
_foreach<span class="operator">(</span>IxClass<span class="operator"> *</span> pClass<span class="operator">, (*</span> pAllClasses<span class="operator">))
{</span><span class="flow"> if</span><span class="operator"> (</span>pClass<span class="operator">) {</span> sDump<span class="operator"> +=</span> pClass<span class="operator">-&gt;</span>dumpClass<span class="operator">(); } }</span>
qDebug<span class="operator">(</span><span class="string">"[QxOrm] %s"</span><span class="operator">,</span><span class="string"> "end dump all registered classes"</span><span class="operator">);</span><span class="flow">
return</span> sDump<span class="operator">;
}</span>
QString IxClass<span class="operator">::</span>dumpClass<span class="operator">()</span><span class="keyword"> const</span><span class="operator">
{</span>
QString sDump<span class="operator">;</span>
sDump<span class="operator"> +=</span><span class="string"> "-- class '"</span><span class="operator"> +</span> m_sKey<span class="operator"> +</span><span class="string"> "' (name '"</span><span class="operator"> +</span> m_sName<span class="operator"> +</span><span class="string"> "', "</span><span class="operator">;</span>
sDump<span class="operator"> +=</span><span class="string"> "description '"</span><span class="operator"> +</span> m_sDescription<span class="operator"> +</span><span class="string"> "', version '"</span><span class="operator"> +</span> QString<span class="operator">::</span>number<span class="operator">(</span>m_lVersion<span class="operator">) +</span><span class="string"> "', "</span><span class="operator">;</span>
sDump<span class="operator"> +=</span><span class="string"> "base class '"</span><span class="operator"> + (</span>getBaseClass<span class="operator">() ?</span> getBaseClass<span class="operator">()-&gt;</span>getKey<span class="operator">() :</span><span class="string"> ""</span><span class="operator">) +</span><span class="string"> "')\n"</span><span class="operator">;</span><span class="type">
long</span> lCount<span class="operator"> = (</span>m_pDataMemberX<span class="operator"> ?</span> m_pDataMemberX<span class="operator">-&gt;</span>count<span class="operator">() :</span><span class="int"> 0</span><span class="operator">);</span>
sDump<span class="operator"> +=</span><span class="string"> "\t* list of registered properties ("</span><span class="operator"> +</span> QString<span class="operator">::</span>number<span class="operator">(</span>lCount<span class="operator">) +</span><span class="string"> ")\n"</span><span class="operator">;</span><span class="flow">
if</span><span class="operator"> (</span>m_pDataMemberX<span class="operator">)
{</span>
IxDataMember<span class="operator"> *</span> pId<span class="operator"> =</span><span class="keyword"> this</span><span class="operator">-&gt;</span>getId<span class="operator">();</span><span class="flow">
for</span><span class="operator"> (</span><span class="type">long</span> l<span class="operator"> =</span><span class="int"> 0</span><span class="operator">;</span> l<span class="operator"> &lt;</span> lCount<span class="operator">;</span> l<span class="operator">++)
{</span>
IxDataMember<span class="operator"> *</span> p<span class="operator"> =</span> m_pDataMemberX<span class="operator">-&gt;</span>get<span class="operator">(</span>l<span class="operator">);</span><span class="flow"> if</span><span class="operator"> (!</span> p<span class="operator">) {</span><span class="flow"> continue</span><span class="operator">; }</span>
IxSqlRelation<span class="operator"> *</span> pRelation<span class="operator"> =</span> p<span class="operator">-&gt;</span>getSqlRelation<span class="operator">();</span>
QString sInfos<span class="operator"> =</span> p<span class="operator">-&gt;</span>getKey<span class="operator">() + ((</span>p<span class="operator"> ==</span> pId<span class="operator">) ?</span> QString<span class="operator">(</span><span class="string">" (id)"</span><span class="operator">) :</span> QString<span class="operator">());</span>
sInfos<span class="operator"> += (</span>pRelation<span class="operator"> ? (</span>QString<span class="operator">(</span><span class="string">" ("</span><span class="operator">) +</span> pRelation<span class="operator">-&gt;</span>getDescription<span class="operator">() +</span> QString<span class="operator">(</span><span class="string">")"</span><span class="operator">)) :</span> QString<span class="operator">());</span>
sDump<span class="operator"> +=</span><span class="string"> "\t\t"</span><span class="operator"> +</span> sInfos<span class="operator"> +</span><span class="string"> "\n"</span><span class="operator">;
}
}</span>
lCount<span class="operator"> = (</span>m_pFctMemberX<span class="operator"> ?</span> m_pFctMemberX<span class="operator">-&gt;</span>count<span class="operator">() :</span><span class="int"> 0</span><span class="operator">);</span>
sDump<span class="operator"> +=</span><span class="string"> "\t* list of registered functions ("</span><span class="operator"> +</span> QString<span class="operator">::</span>number<span class="operator">(</span>lCount<span class="operator">) +</span><span class="string"> ")\n"</span><span class="operator">;</span><span class="flow">
if</span><span class="operator"> (</span>m_pFctMemberX<span class="operator">)
{</span>
_foreach_if<span class="operator">(</span>IxFunction_ptr p<span class="operator">, (*</span> m_pFctMemberX<span class="operator">), (</span>p<span class="operator">))
{</span> QString sKey<span class="operator"> =</span> p<span class="operator">-&gt;</span>getKey<span class="operator">();</span> sDump<span class="operator"> +=</span><span class="string"> "\t\t"</span><span class="operator"> +</span> sKey<span class="operator"> +</span><span class="string"> "\n"</span><span class="operator">; }
}</span>
qDebug<span class="operator">(</span><span class="string">"%s"</span><span class="operator">,</span> qPrintable<span class="operator">(</span>sDump<span class="operator">));</span><span class="flow">
return</span> sDump<span class="operator">;
}</span></pre>
</td>
</tr>
</tbody>
</table>
<br>
Using the function <i>qx::QxClassX::dumpAllClasses()</i> with <a href="./tutorial.html"
target="_blank">qxBlog tutorial</a>, you will obtain following output :<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>Note :</b> you can add some informations to introspection engine using <i>property bag</i>
mechanism.
Indeed, <i>qx::IxClass</i>, <i>qx::IxDataMember</i> and <i>qx::IxFunction</i> classes contain a list
of <i>QVariant</i> items associated to a <i>QString</i> key (see <i>qx::QxPropertyBag</i> class for
more details).<br>
<br>
</td>
</tr>
</tbody>
</table>
<br><br>
<a name="faq_200"><u><b>How to register automatically Qt meta-properties (using <i>Q_PROPERTY</i> macro) to
QxOrm context ?</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">
All classes inherited from <i>QObject</i> type can use <i><a
href="http://doc-snapshots.qt.io/4.8/properties.html" target="_blank">Q_PROPERTY</a></i> macro :
those properties become meta-properties.
This is how Qt framework provides an introspection engine using the <i>moc</i> process.
Meta-properties can be used for example by <i>QML</i> engine, <i>QtScript</i>, etc.<br>
<br>
<b>QxOrm</b> library needs to register each properties per class in the mapping function <i>void
qx::register_class&lt;T&gt;()</i> to provide all features (persistence, XML and binary
serialization, etc.).
It's possible to register automatically all Qt meta-properties into QxOrm context without to manage
any mapping function per class <i>void qx::register_class&lt;T&gt;()</i> :
<b>QX_REGISTER_ALL_QT_PROPERTIES()</b> macro works with Qt introspection engine to iterate over all
meta-properties.<br>
<br>
Here is an example with <i>TestQtProperty</i> class into <i>./test/qxDllSample/dll1/include/</i>
directory of QxOrm package :<br>
<br>
<table border="1" bgcolor="#FFFFFF">
<col>
<tbody>
<tr>
<td title="TestQtProperty.h">
<pre><span class="pre">#ifndef _QX_TEST_QT_META_PROPERTY_H_
#define _QX_TEST_QT_META_PROPERTY_H_
</span><span class="keyword">
class</span> QX_DLL1_EXPORT TestQtProperty<span class="operator"> :</span><span class="keyword"> public</span> QObject<span class="operator">
{</span>
Q_OBJECT
Q_PROPERTY<span class="operator">(</span><span class="type">int</span> id READ id WRITE setId<span class="operator">)</span>
Q_PROPERTY<span class="operator">(</span><span class="type">long</span> number READ number WRITE setNumber<span class="operator">)</span>
Q_PROPERTY<span class="operator">(</span>QString desc READ desc WRITE setDesc<span class="operator">)</span>
Q_PROPERTY<span class="operator">(</span>QDateTime birthDate READ birthDate WRITE setBirthDate<span class="operator">)</span>
Q_PROPERTY<span class="operator">(</span>QVariant photo READ photo WRITE setPhoto<span class="operator">)</span><span class="keyword">
protected</span><span class="operator">:</span><span class="type">
int</span> m_id<span class="operator">;</span><span class="type">
long</span> m_number<span class="operator">;</span>
QString m_desc<span class="operator">;</span>
QDateTime m_birthDate<span class="operator">;</span>
QVariant m_photo<span class="operator">;</span><span class="keyword">
public</span><span class="operator">:</span>
TestQtProperty<span class="operator">() :</span> QObject<span class="operator">(),</span> m_id<span class="operator">(</span><span class="int">0</span><span class="operator">),</span> m_number<span class="operator">(</span><span class="int">0</span><span class="operator">) { ; }</span><span class="keyword">
virtual</span><span class="operator"> ~</span>TestQtProperty<span class="operator">() { ; }</span><span class="type">
int</span> id<span class="operator">()</span><span class="keyword"> const</span><span class="operator"> {</span><span class="flow"> return</span> m_id<span class="operator">; }</span><span class="type">
long</span> number<span class="operator">()</span><span class="keyword"> const</span><span class="operator"> {</span><span class="flow"> return</span> m_number<span class="operator">; }</span>
QString desc<span class="operator">()</span><span class="keyword"> const</span><span class="operator"> {</span><span class="flow"> return</span> m_desc<span class="operator">; }</span>
QDateTime birthDate<span class="operator">()</span><span class="keyword"> const</span><span class="operator"> {</span><span class="flow"> return</span> m_birthDate<span class="operator">; }</span>
QVariant photo<span class="operator">()</span><span class="keyword"> const</span><span class="operator"> {</span><span class="flow"> return</span> m_photo<span class="operator">; }</span><span class="type">
void</span> setId<span class="operator">(</span><span class="type">int</span> i<span class="operator">) {</span> m_id<span class="operator"> =</span> i<span class="operator">; }</span><span class="type">
void</span> setNumber<span class="operator">(</span><span class="type">long</span> l<span class="operator">) {</span> m_number<span class="operator"> =</span> l<span class="operator">; }</span><span class="type">
void</span> setDesc<span class="operator">(</span><span class="keyword">const</span> QString<span class="operator"> &amp;</span> s<span class="operator">) {</span> m_desc<span class="operator"> =</span> s<span class="operator">; }</span><span class="type">
void</span> setBirthDate<span class="operator">(</span><span class="keyword">const</span> QDateTime<span class="operator"> &amp;</span> dt<span class="operator">) {</span> m_birthDate<span class="operator"> =</span> dt<span class="operator">; }</span><span class="type">
void</span> setPhoto<span class="operator">(</span><span class="keyword">const</span> QVariant<span class="operator"> &amp;</span> v<span class="operator">) {</span> m_photo<span class="operator"> =</span> v<span class="operator">; }
};</span>
QX_REGISTER_HPP_QX_DLL1<span class="operator">(</span>TestQtProperty<span class="operator">,</span> QObject<span class="operator">,</span><span class="int"> 0</span><span class="operator">)</span><span class="pre">
#endif // _QX_TEST_QT_META_PROPERTY_H_</span></pre>
</td>
</tr>
</tbody>
</table>
<br>
<table border="1" bgcolor="#FFFFFF">
<col>
<tbody>
<tr>
<td title="TestQtProperty.cpp">
<pre><span class="pre">#include "../include/precompiled.h"
#include "../include/TestQtProperty.h"
#include &lt;QxOrm_Impl.h&gt;
</span>
QX_REGISTER_CPP_QX_DLL1<span class="operator">(</span>TestQtProperty<span class="operator">)</span>
QX_REGISTER_ALL_QT_PROPERTIES<span class="operator">(</span>TestQtProperty<span class="operator">,</span><span class="string"> "id"</span><span class="operator">)</span></pre>
</td>
</tr>
</tbody>
</table>
<br>
If you don't want to use <i>QX_REGISTER_ALL_QT_PROPERTIES</i> macro, you can write 4 lines of code
:<br>
<br>
<table border="1" bgcolor="#FFFFFF">
<col>
<tbody>
<tr>
<td>
<pre><span class="keyword">namespace</span> qx<span class="operator"> {</span><span class="keyword">
template</span><span class="operator"> &lt;&gt;</span><span class="type"> void</span> register_class<span class="operator">(</span>QxClass<span class="operator">&lt;</span>TestQtProperty<span class="operator">&gt; &amp;</span> t<span class="operator">)
{</span> qx<span class="operator">::</span>register_all_qt_properties<span class="operator">&lt;</span>TestQtProperty<span class="operator">&gt;(</span>t<span class="operator">,</span><span class="string"> "id"</span><span class="operator">); }
}</span><span class="comment"> // namespace qx</span></pre>
</td>
</tr>
</tbody>
</table>
<br>
<b>Note :</b> the second parameter of <i>QX_REGISTER_ALL_QT_PROPERTIES</i> macro is the name of the
property mapped to the primary key into database.
If this parameter is empty, then the class doesn't have any primary key or the primary key has been
registered in a base class.<br>
<br>
All properties defined with <i>Q_PROPERTY</i> macro can be registered in QxOrm context in two
different ways :<br>
<b>1-</b> with the classic method : <i>t.data(& MyQObject::my_property, "my_property", 0);</i><br>
<b>2-</b> or without writing the data-member pointer : <i>t.data("my_property", 0);</i><br>
<br>
You can use the first or the second method to register your properties into QxOrm context and access
to the same functionalities using the common interface <i><a
href="../doxygen/html/classqx_1_1_ix_data_member.html" target="_blank">qx::IxDataMember</a></i>.
You can also mix Qt meta-properties and classic registration data-member into the same mapping
function <i>void qx::register_class&lt;T&gt;()</i>.
Each registration method has some advantages and disadvantages.<br>
<br>
Here is the list of advantages using the second registration method into QxOrm context :
<ul>
<li>much more faster to compile ;</li>
<li>reduce exec size ;</li>
<li>strong integration with Qt introspection/<i>moc</i> engine ;</li>
<li>no need to manage any mapping function per class using <i>QX_REGISTER_ALL_QT_PROPERTIES</i>
macro.</li>
</ul>
Here is the list of disadvantages compared to the classic registration method :
<ul>
<li>need to inherit from <i>QObject</i> class to use <i>Q_PROPERTY</i> macro ;</li>
<li>program execution more slower (<i>QVariant</i> type versus C++ <i>template</i>) ;</li>
<li>doesn't support relation between tables into database (<i>one-to-one</i>, <i>one-to-many</i>,
<i>many-to-one</i> and <i>many-to-many</i>) ;
</li>
<li>cannot access to the data-member pointer of a class (need to convert to <i>QVariant</i> type
before to access or to modify a value).</li>
</ul>
</td>
</tr>
</tbody>
</table>
<br><br>
<a name="faq_210"><u><b>How to build a query without writing SQL with the class <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">
The class <i><a href="../doxygen/html/classqx_1_1_qx_sql_query.html"
target="_blank">qx::QxSqlQuery</a></i> (or its typedef <i>qx_query</i>) is used to communicate
with database (to filter, to sort, etc.) in two different ways :
<ul>
<li>writing manually SQL query ;</li>
<li>using C++ methods with a syntax similar to SQL (same concept than the great library <a
href="http://subsonicproject.com/docs/Simple_Query_Tool" target="_blank">SubSonic for .Net</a>).
</li>
</ul>
With the first method (writing manually SQL query), you can use some optimizations specific for each
database.<br>
The second method (using C++ code to build SQL query) binds automatically SQL parameters without using
<i>qx::QxSqlQuery::bind()</i> function.<br>
<br>
Here is an example with <i>qx::QxSqlQuery</i> class writing manually a SQL query :<br>
<br>
<table border="1" bgcolor="#FFFFFF">
<col>
<tbody>
<tr>
<td>
<pre><span class="comment">// Build a SQL query to fetch only 'author' of type 'female'
</span>qx<span class="operator">::</span>QxSqlQuery query<span class="operator">(</span><span class="string">"WHERE author.sex = :sex"</span><span class="operator">);</span>
query<span class="operator">.</span>bind<span class="operator">(</span><span class="string">":sex"</span><span class="operator">,</span> author<span class="operator">::</span>female<span class="operator">);</span>
QList<span class="operator">&lt;</span>author<span class="operator">&gt;</span> list_of_female<span class="operator">;</span>
QSqlError daoError<span class="operator"> =</span> qx<span class="operator">::</span>dao<span class="operator">::</span>fetch_by_query<span class="operator">(</span>query<span class="operator">,</span> list_of_female<span class="operator">);</span><span class="flow">
for</span><span class="operator"> (</span><span class="type">long</span> l<span class="operator"> =</span><span class="int"> 0</span><span class="operator">;</span> l<span class="operator"> &lt;</span> list_of_female<span class="operator">.</span>count<span class="operator">();</span> l<span class="operator">++)
{</span><span class="comment"> /* here we can work with the collection provided by database */</span><span class="operator"> }</span></pre>
</td>
</tr>
</tbody>
</table>
<br>
QxOrm library provides 3 styles to write SQL parameters.<br>
This style can be modified for a project using the following method
<i>qx::QxSqlDatabase::getSingleton()->setSqlPlaceHolderStyle()</i> :<br>
<ul>
<li><i>ph_style_2_point_name</i> : "WHERE author.sex = :sex" (default style) ;</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>
Here is the same example using C++ code of the class <i>qx::QxSqlQuery</i> (or its typedef
<i>qx_query</i>) to build query automatically :<br>
<br>
<table border="1" bgcolor="#FFFFFF">
<col>
<tbody>
<tr>
<td>
<pre><span class="comment">// Build a SQL query to fetch only 'author' of type 'female'
</span>qx_query query<span class="operator">;</span>
query<span class="operator">.</span>where<span class="operator">(</span><span class="string">"author.sex"</span><span class="operator">).</span>isEqualTo<span class="operator">(</span>author<span class="operator">::</span>female<span class="operator">);</span>
QList<span class="operator">&lt;</span>author<span class="operator">&gt;</span> list_of_female<span class="operator">;</span>
QSqlError daoError<span class="operator"> =</span> qx<span class="operator">::</span>dao<span class="operator">::</span>fetch_by_query<span class="operator">(</span>query<span class="operator">,</span> list_of_female<span class="operator">);</span><span class="flow">
for</span><span class="operator"> (</span><span class="type">long</span> l<span class="operator"> =</span><span class="int"> 0</span><span class="operator">;</span> l<span class="operator"> &lt;</span> list_of_female<span class="operator">.</span>count<span class="operator">();</span> l<span class="operator">++)
{</span><span class="comment"> /* here we can work with the collection provided by database */</span><span class="operator"> }</span></pre>
</td>
</tr>
</tbody>
</table>
<br>
With C++ methods of <i>qx::QxSqlQuery</i> class, you don't have to bind any SQL parameter, and the
syntax is similar to real SQL.<br>
All SQL parameters will be provided to database automatically with the following style :
<i>qx::QxSqlDatabase::getSingleton()->getSqlPlaceHolderStyle()</i>.<br>
<br>
Here is an example with many methods of <i>qx::QxSqlQuery</i> class (or its typedef <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>
This code will produce following SQL for <i>MySQL</i>, <i>PostgreSQL</i> and <i>SQLite</i> databases
(for <i>Oracle</i> and <i>SQLServer</i>, there is a specific process for <i>limit()</i> method) :<br>
<br>
<table border="1" bgcolor="#FFFFFF">
<col>
<tbody>
<tr>
<td>
<pre>WHERE sex<span class="operator"> = :</span>sex_1_0
AND age<span class="operator"> &gt; :</span>age_3_0
OR last_name<span class="operator"> &lt;&gt; :</span>last_name_5_0
OR first_name LIKE<span class="operator"> :</span>first_name_7_0
AND<span class="operator"> (</span> id<span class="operator"> &lt;= :</span>id_10_0 AND birth_date BETWEEN<span class="operator"> :</span>birth_date_12_0_1 AND<span class="operator"> :</span>birth_date_12_0_2<span class="operator"> )</span>
OR id IN<span class="operator"> (:</span>id_15_0_0<span class="operator">, :</span>id_15_0_1<span class="operator">, :</span>id_15_0_2<span class="operator">, :</span>id_15_0_3<span class="operator">, :</span>id_15_0_4<span class="operator">)</span>
AND is_deleted IS NOT NULL
ORDER BY last_name ASC<span class="operator">,</span> first_name ASC<span class="operator">,</span> sex ASC
LIMIT<span class="operator"> :</span>limit_rows_count_19_0 OFFSET<span class="operator"> :</span>offset_start_row_19_0</pre>
</td>
</tr>
</tbody>
</table>
<br>
Here is the list of all functions available to use <i>qx::QxSqlQuery</i> class (or its typedef
<i>qx_query</i>) :<br>
<br>
<table border="1" bgcolor="#FFFFFF">
<col>
<tbody>
<tr>
<td>
<pre><span class="comment">// with functions into namespace qx::dao
</span>qx<span class="operator">::</span>dao<span class="operator">::</span>count<span class="operator">&lt;</span>T<span class="operator">&gt;()</span>
qx<span class="operator">::</span>dao<span class="operator">::</span>fetch_by_query<span class="operator">&lt;</span>T<span class="operator">&gt;()</span>
qx<span class="operator">::</span>dao<span class="operator">::</span>update_by_query<span class="operator">&lt;</span>T<span class="operator">&gt;()</span>
qx<span class="operator">::</span>dao<span class="operator">::</span>delete_by_query<span class="operator">&lt;</span>T<span class="operator">&gt;()</span>
qx<span class="operator">::</span>dao<span class="operator">::</span>destroy_by_query<span class="operator">&lt;</span>T<span class="operator">&gt;()</span>
qx<span class="operator">::</span>dao<span class="operator">::</span>fetch_by_query_with_relation<span class="operator">&lt;</span>T<span class="operator">&gt;()</span>
qx<span class="operator">::</span>dao<span class="operator">::</span>fetch_by_query_with_all_relation<span class="operator">&lt;</span>T<span class="operator">&gt;()</span>
qx<span class="operator">::</span>dao<span class="operator">::</span>update_by_query_with_relation<span class="operator">&lt;</span>T<span class="operator">&gt;()</span>
qx<span class="operator">::</span>dao<span class="operator">::</span>update_by_query_with_all_relation<span class="operator">&lt;</span>T<span class="operator">&gt;()</span>
qx<span class="operator">::</span>dao<span class="operator">::</span>update_optimized_by_query<span class="operator">&lt;</span>T<span class="operator">&gt;()</span><span class="comment">
// with qx::QxSession class
</span>qx<span class="operator">::</span>QxSession<span class="operator">::</span>count<span class="operator">&lt;</span>T<span class="operator">&gt;()</span>
qx<span class="operator">::</span>QxSession<span class="operator">::</span>fetchByQuery<span class="operator">&lt;</span>T<span class="operator">&gt;()</span>
qx<span class="operator">::</span>QxSession<span class="operator">::</span>update<span class="operator">&lt;</span>T<span class="operator">&gt;()</span>
qx<span class="operator">::</span>QxSession<span class="operator">::</span>deleteByQuery<span class="operator">&lt;</span>T<span class="operator">&gt;()</span>
qx<span class="operator">::</span>QxSession<span class="operator">::</span>destroyByQuery<span class="operator">&lt;</span>T<span class="operator">&gt;()</span><span class="comment">
// with qx::QxRepository&lt;T&gt; class
</span>qx<span class="operator">::</span>QxRepository<span class="operator">&lt;</span>T<span class="operator">&gt;::</span>count<span class="operator">()</span>
qx<span class="operator">::</span>QxRepository<span class="operator">&lt;</span>T<span class="operator">&gt;::</span>fetchByQuery<span class="operator">()</span>
qx<span class="operator">::</span>QxRepository<span class="operator">&lt;</span>T<span class="operator">&gt;::</span>update<span class="operator">()</span>
qx<span class="operator">::</span>QxRepository<span class="operator">&lt;</span>T<span class="operator">&gt;::</span>deleteByQuery<span class="operator">()</span>
qx<span class="operator">::</span>QxRepository<span class="operator">&lt;</span>T<span class="operator">&gt;::</span>destroyByQuery<span class="operator">()</span></pre>
</td>
</tr>
</tbody>
</table>
<br>
<b>Note :</b> those functions have 2 other optionals parameters :
<ul>
<li><i>const QStringList & columns</i> : to indicate columns to fetch (by default, all columns are
fetched) ;</li>
<li><i>const QStringList & relation</i> : to indicate relations to fetch (<i>one-to-one</i>,
<i>one-to-many</i>, <i>many-to-one</i> and <i>many-to-many</i> defined into <i>void
qx::register_class&lt;T&gt;()</i> mapping function by class), by default there is no relation
fetched.
</li>
</ul>
</td>
</tr>
</tbody>
</table>
<br><br>
<a name="faq_220"><u><b>How to use the cache (functions into <i>namespace</i> <i>qx::cache</i>) of QxOrm
library ?</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">
Cache engine provided by QxOrm library (<a href="../doxygen/html/group___qx_cache.html"
target="_blank"><i>QxCache</i> module</a>) is <i>thread-safe</i> and can store easily any kind of
objects.<br>
Functions to access to the cache engine are inside <a href="../doxygen/html/namespaceqx_1_1cache.html"
target="_blank"><i>namespace</i> <i>qx::cache</i></a>.<br>
<i>qx::cache</i> engine can provide a program optimization : you can for example store items fetched
by a query to database.<br>
<br>
Each item into the cache is associated with a key of type <i>QString</i> : this key provides a quick
access to an item stored into the cache.<br>
If a new item is inserted with a key already in the cache, then the old item associated with this key
is removed automatically from the cache.<br>
<br>
Cache engine of QxOrm library doesn't manage memory : there is no <i>delete</i> called by the cache
engine.<br>
This is why it's strongly recommended (but not an obligation) to store smart-pointers into the cache :
for example, <a href="http://www.boost.org/doc/libs/release/libs/smart_ptr/shared_ptr.htm"
target="_blank"><i>boost::shared_ptr&lt;T&gt;</i></a> of <i>boost</i> library or <a
href="http://doc-snapshots.qt.io/4.8/qsharedpointer.html"
target="_blank"><i>QSharedPointer&lt;T&gt;</i></a> of <i>Qt</i> library.<br>
<br>
Cache engine can have a max cost to avoid too much memory usage : each item inserted to the cache can
be associated with a cost (for example, element's count of a collection).<br>
When the limit (max cost) of the cache engine is reached, first items inserted to the cache are
automatically removed (insertion order) until limit of the cache is ok.<br>
<br>
It's also possible to associate a date-time insertion when an item is added to the cache.<br>
If there is no date-time, then the current date-time is taken into account.<br>
This feature provides a way to verify that an item stored into the cache must be updated or not.<br>
<br>
Here is an example using cache engine of QxOrm library (functions into <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">// Define max cost of cache engine to 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">
// Fetch a list of 'author' from database
</span>boost<span class="operator">::</span>shared_ptr<span class="operator">&lt;</span> QList<span class="operator">&lt;</span>author<span class="operator">&gt; &gt;</span> list_author<span class="operator">;</span>
QSqlError daoError<span class="operator"> =</span> qx<span class="operator">::</span>dao<span class="operator">::</span>fetch_all<span class="operator">(</span>list_author<span class="operator">);</span><span class="comment">
// Insert the list of 'author' to the 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">
// Fetch a list of 'blog' from database
</span>QSharedPointer<span class="operator">&lt;</span> std<span class="operator">::</span>vector<span class="operator">&lt;</span>blog<span class="operator">&gt; &gt;</span> list_blog<span class="operator">;</span>
daoError<span class="operator"> =</span> qx<span class="operator">::</span>dao<span class="operator">::</span>fetch_all<span class="operator">(</span>list_blog<span class="operator">);</span><span class="comment">
// Insert the list of 'blog' to the cache (cost = 'blog' count)
</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">
// Pointer to an object of 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">
// Insert 'comment' to the cache with a date-time insertion
</span>qx<span class="operator">::</span>cache<span class="operator">::</span>set<span class="operator">(</span><span class="string">"comment"</span><span class="operator">,</span> my_comment<span class="operator">,</span><span class="int"> 1</span><span class="operator">,</span> my_comment<span class="operator">-&gt;</span>dateModif<span class="operator">());</span><span class="comment">
// Get the list of 'blog' stored into the cache
</span>list_blog<span class="operator"> =</span> qx<span class="operator">::</span>cache<span class="operator">::</span>get<span class="operator">&lt;</span> QSharedPointer<span class="operator">&lt;</span> std<span class="operator">::</span>vector<span class="operator">&lt;</span>blog<span class="operator">&gt; &gt; &gt;(</span><span class="string">"list_blog"</span><span class="operator">);</span><span class="comment">
// Get the list of 'blog' without providing the 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">
// Remove list of 'author' from cache
</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">
// Get items count stored into the 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">
// Get current cost of items stored into the 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">
// Verify that an element with the key "comment" exists into the 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">
// Get 'comment' stored into the cache with its date-time 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">
// Clear the 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>How to build SQL schema (create and update tables) based on C++ persistents classes
registered in QxOrm context ?</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">It's recommended to use <b>QxEntityEditor</b> application to manage SQL schema
generation.</a><br>
<br>
QxOrm library doesn't provide a generator to create and to update automatically tables into
database.<br>
Indeed, <i>qx::dao::create_table&lt;T&gt;</i> function must be used only to create prototypes or
samples.<br>
It's strongly recommended to work with a tool provided by each SGBD to design and to manage tables
into database (for example <i>Navicat</i> with <i>MySql</i>, <i>pgAdmin</i> with <i>PostgreSQL</i>,
<i>SQLite Manager</i> with <i>SQLite</i>, etc.).<br>
Moreover, each tool provided by each SGBD can add some optimizations to the database (add some indexes
for example).<br>
<br>
But sometimes, it can be useful to not have to manage manually tables into database.<br>
In this case, it's possible to create a C++ function to iterate over all persistents classes
registered in QxOrm context (using introspection engine of QxOrm library) : so you can build a SQL
script to create and to update tables into database.<br>
<br>
QxOrm library provides an example of a C++ function : based on this function, you can create your own
function to build SQL schema.<br>
This QxOrm function is written in the file <i><a href="./resource/qxclassx_dump_sql_schema.html"
target="_blank">./src/QxRegister/QxClassX.cpp</a></i> and is called <i><a
href="./resource/qxclassx_dump_sql_schema.html" target="_blank">QString
qx::QxClassX::dumpSqlSchema()</a></i>.<br>
This QxOrm function builds a SQL script and returns a <i>QString</i> value : it's also possible to
modify the function to generate a file with SQL script or to execute each SQL process directly to the
SGBD.<br>
<br>
Here is a sample implementation provided by <a
href="http://www.developpez.net/forums/u449556/dodobibi/" target="_blank">dodobibi</a> to manage a
<i>PostgreSQL</i> database : this sample works with a version number to add columns to existing
tables, to add some indexes to existing columns, etc.<br>
When you start your application, a version number is provided and incremented when a new version of
your application is released :<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"></span></pre>
</td>
</tr>
</tbody>
</table>
<br>
A table into the database must be created to store this version number.<br>
A C++ persistent class is mapped to this table :<br>
<br>
<table border="1" bgcolor="#FFFFFF">
<col>
<tbody>
<tr>
<td>
<pre><span class="pre">#ifndef _DATABASE_VERSION_H_
#define _DATABASE_VERSION_H_
</span><span class="keyword">
class</span> MY_DLL_EXPORT DatabaseVersion<span class="operator">
{</span><span class="keyword">
public</span><span class="operator">:</span>
QString name<span class="operator">;</span><span class="type">
long</span> version<span class="operator">;
};</span>
QX_REGISTER_HPP_MY_APP<span class="operator">(</span>DatabaseVersion<span class="operator">,</span> qx<span class="operator">::</span>trait<span class="operator">::</span>no_base_class_defined<span class="operator">,</span><span class="int"> 0</span><span class="operator">)</span><span class="pre">
#endif // _DATABASE_VERSION_H_</span></pre>
</td>
</tr>
</tbody>
</table>
<br>
<table border="1" bgcolor="#FFFFFF">
<col>
<tbody>
<tr>
<td>
<pre><span class="pre">#include "../include/precompiled.h"
#include "../include/DatabaseVersion.h"
#include &lt;QxOrm_Impl.h&gt;
</span>
QX_REGISTER_CPP_MY_APP<span class="operator">(</span>DatabaseVersion<span class="operator">)</span><span class="keyword">
namespace</span> qx<span class="operator"> {</span><span class="keyword">
template</span><span class="operator"> &lt;&gt;</span><span class="type"> void</span> register_class<span class="operator">(</span>QxClass<span class="operator">&lt;</span>DatabaseVersion<span class="operator">&gt; &amp;</span> t<span class="operator">)
{</span>
t<span class="operator">.</span>id<span class="operator">(&amp;</span> DatabaseVersion<span class="operator">::</span>name<span class="operator">,</span><span class="string"> "name"</span><span class="operator">);</span>
t<span class="operator">.</span>data<span class="operator">(&amp;</span> DatabaseVersion<span class="operator">::</span>version<span class="operator">,</span><span class="string"> "version"</span><span class="operator">);
}}</span></pre>
</td>
</tr>
</tbody>
</table>
<br>
With <i>DatabaseVersion</i> class, it's possible to verify that the database must be updated or
not.<br>
This is the goal of <i>isDatabaseVersionOld()</i> function :<br>
<br>
<table border="1" bgcolor="#FFFFFF">
<col>
<tbody>
<tr>
<td>
<pre><span class="type">bool</span> isDatabaseVersionOld<span class="operator">()
{</span>
DatabaseVersion dbVersion<span class="operator">;</span>
dbVersion<span class="operator">.</span>name<span class="operator"> =</span><span class="string"> "MyAppName"</span><span class="operator">;</span>
QSqlError err<span class="operator"> =</span> qx<span class="operator">::</span>dao<span class="operator">::</span>fetch_by_id<span class="operator">(</span>dbVersion<span class="operator">);</span><span class="flow">
if</span><span class="operator"> (</span>err<span class="operator">.</span>isValid<span class="operator">()) {</span> qAssert<span class="operator">(</span><span class="bool">false</span><span class="operator">);</span><span class="flow"> return</span><span class="bool"> false</span><span class="operator">; }</span><span class="flow">
return</span><span class="operator"> (</span>dbVersion<span class="operator">.</span>version<span class="operator"> &lt;</span> qApp<span class="operator">-&gt;</span>property<span class="operator">(</span><span class="string">"DomainVersion"</span><span class="operator">).</span>toInt<span class="operator">());
}</span></pre>
</td>
</tr>
</tbody>
</table>
<br>
If <i>isDatabaseVersionOld()</i> function returns <i>true</i> when you start your application, then
you must update your SQL schema :<br>
<br>
<table border="1" bgcolor="#FFFFFF">
<col>
<tbody>
<tr>
<td>
<pre><span class="type">void</span> updateDatabaseVersion<span class="operator">()
{</span><span class="flow">
try</span><span class="operator">
{</span><span class="type">
int</span> domainVersion<span class="operator"> =</span> qApp<span class="operator">-&gt;</span>property<span class="operator">(</span><span class="string">"DomainVersion"</span><span class="operator">).</span>toInt<span class="operator">();</span><span class="comment">
// Connect to the database with a user with modifications rights on SQL schema
</span> QSqlDatabase db<span class="operator"> =</span> qx<span class="operator">::</span>QxSqlDatabase<span class="operator">::</span>getSingleton<span class="operator">()-&gt;</span>getDatabaseCloned<span class="operator">();</span>
db<span class="operator">.</span>setUserName<span class="operator">(</span><span class="string">"MyAdminLogin"</span><span class="operator">);</span>
db<span class="operator">.</span>setPassword<span class="operator">(</span><span class="string">"MyAdminPassword"</span><span class="operator">);</span><span class="comment">
// Create a session, open automatically a transaction and throw an exception when an error occured
</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">
// Fetch the database version with a lock to protect the database
</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">
// When unlocked for other users, verify that the database must be updated or not
</span><span class="flow"> if</span><span class="operator"> (</span>dbVersion<span class="operator">.</span>version<span class="operator"> &gt;=</span> domainVersion<span class="operator">) {</span><span class="flow"> return</span><span class="operator">; }</span><span class="comment">
// Execute each SQL process with "query" variable
</span> QSqlQuery query<span class="operator">(</span>db<span class="operator">);</span><span class="comment">
// Fetch all C++ persistents classes registered in QxOrm context
</span> qx<span class="operator">::</span>QxCollection<span class="operator">&lt;</span>QString<span class="operator">,</span> qx<span class="operator">::</span>IxClass<span class="operator"> *&gt; *</span> pAllClasses<span class="operator"> =</span> qx<span class="operator">::</span>QxClassX<span class="operator">::</span>getAllClasses<span class="operator">();</span><span class="flow">
if</span><span class="operator"> (!</span> pAllClasses<span class="operator">) {</span> qAssert<span class="operator">(</span><span class="bool">false</span><span class="operator">);</span><span class="flow"> return</span><span class="operator">; }</span><span class="comment">
// Fetch all tables into database (this is a Qt function)
</span> QStringList tables<span class="operator"> =</span> db<span class="operator">.</span>tables<span class="operator">();</span><span class="flow">
for</span><span class="operator"> (</span><span class="type">long</span> k<span class="operator"> =</span><span class="int"> 0</span><span class="operator">;</span> k<span class="operator"> &lt;</span> pAllClasses<span class="operator">-&gt;</span>count<span class="operator">();</span> k<span class="operator">++)
{</span>
qx<span class="operator">::</span>IxClass<span class="operator"> *</span> pClass<span class="operator"> =</span> pAllClasses<span class="operator">-&gt;</span>getByIndex<span class="operator">(</span>k<span class="operator">);</span><span class="flow">
if</span><span class="operator"> (!</span> pClass<span class="operator">) {</span><span class="flow"> continue</span><span class="operator">; }</span><span class="comment">
// Filter non persitents classes
</span><span class="flow"> if</span><span class="operator"> (</span>pClass<span class="operator">-&gt;</span>isKindOf<span class="operator">(</span><span class="string">"qx::service::IxParameter"</span><span class="operator">) ||</span> pClass<span class="operator">-&gt;</span>isKindOf<span class="operator">(</span><span class="string">"qx::service::IxService"</span><span class="operator">)) {</span><span class="flow"> continue</span><span class="operator">; }</span><span class="comment">
// Filter already updated classes
</span><span class="flow"> if</span><span class="operator"> (</span>pClass<span class="operator">-&gt;</span>getVersion<span class="operator">() &lt;=</span> dbVersion<span class="operator">.</span>version<span class="operator">) {</span><span class="flow"> continue</span><span class="operator">; }</span><span class="comment">
// If table doesn't exist, create it and set the owner
</span><span class="flow"> if</span><span class="operator"> (!</span> tables<span class="operator">.</span>contains<span class="operator">(</span>pClass<span class="operator">-&gt;</span>getName<span class="operator">()))
{</span>
query<span class="operator">.</span>exec<span class="operator">(</span><span class="string">"CREATE TABLE "</span><span class="operator"> +</span> pClass<span class="operator">-&gt;</span>getName<span class="operator">() +</span><span class="string"> " ( ) WITH (OIDS = FALSE);"
"ALTER TABLE "</span><span class="operator"> +</span> pClass<span class="operator">-&gt;</span>getName<span class="operator">() +</span><span class="string"> " OWNER TO \"MyAdminLogin\";"</span><span class="operator">);</span>
session<span class="operator"> +=</span> query<span class="operator">.</span>lastError<span class="operator">();
}</span><span class="comment">
// If a column doesn't exist, add it to the table
</span> qx<span class="operator">::</span>IxDataMemberX<span class="operator"> *</span> pDataMemberX<span class="operator"> =</span> pClass<span class="operator">-&gt;</span>getDataMemberX<span class="operator">();</span><span class="flow">
for</span><span class="operator"> (</span><span class="type">long</span> l<span class="operator"> =</span><span class="int"> 0</span><span class="operator">; (</span>pDataMemberX<span class="operator"> &amp;&amp; (</span>l<span class="operator"> &lt;</span> pDataMemberX<span class="operator">-&gt;</span>count_WithDaoStrategy<span class="operator">()));</span> l<span class="operator">++)
{</span>
qx<span class="operator">::</span>IxDataMember<span class="operator"> *</span> p<span class="operator"> =</span> pDataMemberX<span class="operator">-&gt;</span>get_WithDaoStrategy<span class="operator">(</span>l<span class="operator">);</span><span class="flow">
if</span><span class="operator"> (!</span> p<span class="operator"> || (</span>p<span class="operator">-&gt;</span>getVersion<span class="operator">() &lt;=</span> dbVersion<span class="operator">.</span>version<span class="operator">)) {</span><span class="flow"> continue</span><span class="operator">; }</span>
query<span class="operator">.</span>exec<span class="operator">(</span><span class="string">"ALTER TABLE "</span><span class="operator"> +</span> pClass<span class="operator">-&gt;</span>getName<span class="operator">() +</span><span class="string"> " ADD COLUMN "</span><span class="operator"> +</span> p<span class="operator">-&gt;</span>getName<span class="operator">() +</span><span class="string"> " "</span><span class="operator"> +</span> p<span class="operator">-&gt;</span>getSqlType<span class="operator">() +</span><span class="string"> ";"</span><span class="operator">);</span>
session<span class="operator"> +=</span> query<span class="operator">.</span>lastError<span class="operator">();</span><span class="flow">
if</span><span class="operator"> (</span>p<span class="operator">-&gt;</span>getIsPrimaryKey<span class="operator">())</span><span class="comment"> // PRIMARY KEY
</span><span class="operator"> {</span>
query<span class="operator">.</span>exec<span class="operator">(</span><span class="string">"ALTER TABLE "</span><span class="operator"> +</span> pClass<span class="operator">-&gt;</span>getName<span class="operator">() +</span><span class="string"> " ADD PRIMARY KEY ("</span><span class="operator"> +</span> p<span class="operator">-&gt;</span>getName<span class="operator">() +</span><span class="string"> ");"</span><span class="operator">);</span>
session<span class="operator"> +=</span> query<span class="operator">.</span>lastError<span class="operator">();
}</span><span class="flow">
if</span><span class="operator"> (</span>p<span class="operator">-&gt;</span>getAllPropertyBagKeys<span class="operator">().</span>contains<span class="operator">(</span><span class="string">"INDEX"</span><span class="operator">))</span><span class="comment"> // INDEX
</span><span class="operator"> {</span>
query<span class="operator">.</span>exec<span class="operator">(</span><span class="string">"CREATE INDEX "</span><span class="operator"> +</span> pClass<span class="operator">-&gt;</span>getName<span class="operator">() +</span><span class="string"> "_"</span><span class="operator"> +</span> p<span class="operator">-&gt;</span>getName<span class="operator">() +</span><span class="string"> "_idx"</span><span class="operator"> +</span><span class="string">
" ON "</span><span class="operator"> +</span> pClass<span class="operator">-&gt;</span>getName<span class="operator">() +</span><span class="string"> " USING "</span><span class="operator"> +</span> p<span class="operator">-&gt;</span>getPropertyBag<span class="operator">(</span><span class="string">"INDEX"</span><span class="operator">).</span>toString<span class="operator">() +</span><span class="string"> " ("</span><span class="operator"> +</span> p<span class="operator">-&gt;</span>getName<span class="operator">() +</span><span class="string"> ");"</span><span class="operator">);</span>
session<span class="operator"> +=</span> query<span class="operator">.</span>lastError<span class="operator">();
}</span><span class="flow">
if</span><span class="operator"> (</span>p<span class="operator">-&gt;</span>getNotNull<span class="operator">())</span><span class="comment"> // NOT NULL
</span><span class="operator"> {</span>
query<span class="operator">.</span>exec<span class="operator">(</span><span class="string">"ALTER TABLE "</span><span class="operator"> +</span> pClass<span class="operator">-&gt;</span>getName<span class="operator">() +</span><span class="string"> " ALTER COLUMN "</span><span class="operator"> +</span> p<span class="operator">-&gt;</span>getName<span class="operator">() +</span><span class="string"> " SET NOT NULL;"</span><span class="operator">);</span>
session<span class="operator"> +=</span> query<span class="operator">.</span>lastError<span class="operator">();
}</span><span class="flow">
if</span><span class="operator"> (</span>p<span class="operator">-&gt;</span>getAutoIncrement<span class="operator">())</span><span class="comment"> // AUTO INCREMENT
</span><span class="operator"> {</span>
query<span class="operator">.</span>exec<span class="operator">(</span><span class="string">"CREATE SEQUENCE "</span><span class="operator"> +</span> pClass<span class="operator">-&gt;</span>getName<span class="operator">() +</span><span class="string"> "_"</span><span class="operator"> +</span> p<span class="operator">-&gt;</span>getName<span class="operator">() +</span><span class="string"> "_seq"</span><span class="operator"> +</span><span class="string"> "; "
"ALTER TABLE "</span><span class="operator"> +</span> pClass<span class="operator">-&gt;</span>getName<span class="operator">() +</span><span class="string"> "_"</span><span class="operator"> +</span> p<span class="operator">-&gt;</span>getName<span class="operator">() +</span><span class="string"> "_seq"</span><span class="operator"> +</span><span class="string"> " OWNER TO \"MyAdminLogin\"; "
"ALTER TABLE "</span><span class="operator"> +</span> pClass<span class="operator">-&gt;</span>getName<span class="operator">() +</span><span class="string"> " ALTER COLUMN "</span><span class="operator"> +</span> p<span class="operator">-&gt;</span>getName<span class="operator">() +</span><span class="string"> " "</span><span class="operator"> +</span><span class="string">
"SET DEFAULT nextval('"</span><span class="operator"> +</span> pClass<span class="operator">-&gt;</span>getName<span class="operator">() +</span><span class="string"> "_"</span><span class="operator"> +</span> p<span class="operator">-&gt;</span>getName<span class="operator">() +</span><span class="string"> "_seq"</span><span class="operator"> +</span><span class="string"> "'::regclass);"</span><span class="operator">);</span>
session<span class="operator"> +=</span> query<span class="operator">.</span>lastError<span class="operator">();
}</span><span class="flow">
if</span><span class="operator"> (</span>p<span class="operator">-&gt;</span>getDescription<span class="operator">() !=</span><span class="string"> ""</span><span class="operator">)</span><span class="comment"> // DESCRIPTION
</span><span class="operator"> {</span> query<span class="operator">.</span>exec<span class="operator">(</span><span class="string">"COMMENT ON COLUMN "</span><span class="operator"> +</span> pClass<span class="operator">-&gt;</span>getName<span class="operator">() +</span><span class="string"> "."</span><span class="operator"> +</span> p<span class="operator">-&gt;</span>getName<span class="operator">() +</span><span class="string"> " IS $$"</span><span class="operator"> +</span> p<span class="operator">-&gt;</span>getDescription<span class="operator">() +</span><span class="string"> "$$ ;"</span><span class="operator">);</span>
session<span class="operator"> +=</span> query<span class="operator">.</span>lastError<span class="operator">();
}
}
}</span><span class="comment">
// Save current version of the database
</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">
// End of "try" scope : session is destroyed =&gt; commit or rollback automatically
// Moreover, a commit or a rollback unlock the process for all users
</span><span class="operator"> }</span><span class="flow">
catch</span><span class="operator"> (</span><span class="keyword">const</span> qx<span class="operator">::</span>dao<span class="operator">::</span>sql_error<span class="operator"> &amp;</span> err<span class="operator">)
{</span>
QSqlError sqlError<span class="operator"> =</span> err<span class="operator">.</span>get<span class="operator">();</span>
qDebug<span class="operator">() &lt;&lt;</span> sqlError<span class="operator">.</span>databaseText<span class="operator">();</span>
qDebug<span class="operator">() &lt;&lt;</span> sqlError<span class="operator">.</span>driverText<span class="operator">();</span>
qDebug<span class="operator">() &lt;&lt;</span> sqlError<span class="operator">.</span>number<span class="operator">();</span>
qDebug<span class="operator">() &lt;&lt;</span> sqlError<span class="operator">.</span>type<span class="operator">();
}
}</span></pre>
</td>
</tr>
</tbody>
</table>
<br>
<b>Note :</b> this code (like <a href="./resource/qxclassx_dump_sql_schema.html"
target="_blank"><i>qx::QxClassX::dumpSqlSchema()</i></a> function) can be modified to provide more
features.<br>
For example, it could be interesting to create by default another table (like <i>DatabaseVersion</i>
table) to store the list of all persistents classes registered in QxOrm context : instead of using
"<i>db.tables()</i>" Qt function, it could be possible to fetch all tables with more informations
(version number for each table, columns count registered in QxOrm context, table description, etc.).
<br>
</td>
</tr>
</tbody>
</table>
<br><br>
<a name="faq_240"><u><b>How to associate a SQL type to a C++ class ?</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">
Each database provides its own SQL types to store datas.<br>
QxOrm library associates by default some C++ classes frequently used in a program :<br>
<br>
<table border="1" bgcolor="#FFFFFF">
<col>
<tbody>
<tr>
<td>
<pre><span class="string">"bool"</span><span class="operator"> &lt;-&gt;</span><span class="string"> "SMALLINT"
"qx_bool"</span><span class="operator"> &lt;-&gt;</span><span class="string"> "SMALLINT"
"short"</span><span class="operator"> &lt;-&gt;</span><span class="string"> "SMALLINT"
"int"</span><span class="operator"> &lt;-&gt;</span><span class="string"> "INTEGER"
"long"</span><span class="operator"> &lt;-&gt;</span><span class="string"> "INTEGER"
"long long"</span><span class="operator"> &lt;-&gt;</span><span class="string"> "INTEGER"
"float"</span><span class="operator"> &lt;-&gt;</span><span class="string"> "FLOAT"
"double"</span><span class="operator"> &lt;-&gt;</span><span class="string"> "FLOAT"
"long double"</span><span class="operator"> &lt;-&gt;</span><span class="string"> "FLOAT"
"unsigned short"</span><span class="operator"> &lt;-&gt;</span><span class="string"> "SMALLINT"
"unsigned int"</span><span class="operator"> &lt;-&gt;</span><span class="string"> "INTEGER"
"unsigned long"</span><span class="operator"> &lt;-&gt;</span><span class="string"> "INTEGER"
"unsigned long long"</span><span class="operator"> &lt;-&gt;</span><span class="string"> "INTEGER"
"std::string"</span><span class="operator"> &lt;-&gt;</span><span class="string"> "TEXT"
"std::wstring"</span><span class="operator"> &lt;-&gt;</span><span class="string"> "TEXT"
"QString"</span><span class="operator"> &lt;-&gt;</span><span class="string"> "TEXT"
"QVariant"</span><span class="operator"> &lt;-&gt;</span><span class="string"> "TEXT"
"QUuid"</span><span class="operator"> &lt;-&gt;</span><span class="string"> "TEXT"
"QDate"</span><span class="operator"> &lt;-&gt;</span><span class="string"> "DATE"
"QTime"</span><span class="operator"> &lt;-&gt;</span><span class="string"> "TIME"
"QDateTime"</span><span class="operator"> &lt;-&gt;</span><span class="string"> "TIMESTAMP"
"QByteArray"</span><span class="operator"> &lt;-&gt;</span><span class="string"> "BLOB"
"qx::QxDateNeutral"</span><span class="operator"> &lt;-&gt;</span><span class="string"> "TEXT"
"qx::QxTimeNeutral"</span><span class="operator"> &lt;-&gt;</span><span class="string"> "TEXT"
"qx::QxDateTimeNeutral"</span><span class="operator"> &lt;-&gt;</span><span class="string"> "TEXT"</span></pre>
</td>
</tr>
</tbody>
</table>
<br>
If a SQL type provided by default by QxOrm library is not supported by the database, it can be easily
modified (globally for all the application) using the following collection :<br>
<br>
<table border="1" bgcolor="#FFFFFF">
<col>
<tbody>
<tr>
<td>
<pre>QHash<span class="operator">&lt;</span>QString<span class="operator">,</span> QString<span class="operator">&gt; *</span> lstSqlType<span class="operator"> =</span> qx<span class="operator">::</span>QxClassX<span class="operator">::</span>getAllSqlTypeByClassName<span class="operator">();</span>
lstSqlType<span class="operator">-&gt;</span>insert<span class="operator">(</span><span class="string">"QString"</span><span class="operator">,</span><span class="string"> "VARCHAR(255)"</span><span class="operator">);</span>
lstSqlType<span class="operator">-&gt;</span>insert<span class="operator">(</span><span class="string">"std::string"</span><span class="operator">,</span><span class="string"> "VARCHAR(255)"</span><span class="operator">);</span><span class="comment">
// etc.</span></pre>
</td>
</tr>
</tbody>
</table>
<br>
To modify a SQL type for a specific column of a table, you have to define the new SQL type in the
mapping function of QxOrm library :<br>
<br>
<table border="1" bgcolor="#FFFFFF">
<col>
<tbody>
<tr>
<td>
<pre><span class="keyword">namespace</span> qx<span class="operator"> {</span><span class="keyword">
template</span><span class="operator"> &lt;&gt;</span><span class="type"> void</span> register_class<span class="operator">(</span>QxClass<span class="operator">&lt;</span>MyClass<span class="operator">&gt; &amp;</span> t<span class="operator">)
{</span><span class="comment">
//...
</span> IxDataMember<span class="operator"> *</span> p<span class="operator"> =</span> t<span class="operator">.</span>data<span class="operator">(&amp;</span> MyClass<span class="operator">::</span>m_MyProperty<span class="operator">,</span><span class="string"> "my_property"</span><span class="operator">);</span>
p<span class="operator">-&gt;</span>setSqlType<span class="operator">(</span><span class="string">"VARCHAR(255)"</span><span class="operator">);</span><span class="comment">
//...
</span><span class="operator">}}</span></pre>
</td>
</tr>
</tbody>
</table>
<br>
For all classes not supported by default by QxOrm library (see the FAQ : <i><a
href="./faq.html#faq_180">How to persist a type without its source code (class from an external
library for example) ?</a></i>), it's possible to associate a default SQL type using the following
macro (outside all <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>How to use <i>QxValidator</i> module to validate automatically an instance
?</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><a href="../doxygen/html/group___qx_validator.html" target="_blank">QxValidator</a></b> module of
<b>QxOrm</b> library provides a validation engine for classes registered in QxOrm context.<br>
To use this validation engine, you have to define your constraints into the mapping function per class
: <i>void qx::register_class</i>.<br>
If for an instance of class, at least one constraint violation is detected, then the instance is
invalid : the object cannot be saved into database (<i>INSERT</i> or <i>UPDATE</i>).<br>
<br>
It's also possible to use <b>QxValidator</b> module to validate an instance on the presentation layer
: if some datas from a user are invalids, an error message can be displayed, and it's not necessary to
try to send the instance to the data access layer.<br>
The validation mechanism can be executed in different layers in your application without having to
duplicate any of these rules (presentation layer, data access layer).<br>
<br>
Here is a description of some classes defined into <b>QxValidator</b> module :
<ul>
<li><a href="../doxygen/html/classqx_1_1_ix_validator.html" target="_blank">qx::IxValidator</a> :
each constraint defined into <i>void qx::register_class</i> function is associated with an
interface of type <i>qx::IxValidator</i> ;</li>
<li><a href="../doxygen/html/classqx_1_1_ix_validator_x.html" target="_blank">qx::IxValidatorX</a> :
list of constraints is associated with an interface of type <i>qx::IxValidatorX</i>. You can
iterate over this collection during program execution : it could be interesting for example to
generate SQL schema and take into account some validation rules into database (see the FAQ : <a
href="./faq.html#faq_230" target="_blank">How to build SQL schema (create and update tables)
based on C++ persistents classes registered in QxOrm context ?</a>) ;</li>
<li><a href="../doxygen/html/classqx_1_1_qx_invalid_value_x.html"
target="_blank">qx::QxInvalidValueX</a> : when an instance is invalid, list of constraints
violation are inserted into a <i>qx::QxInvalidValueX</i> collection ;</li>
<li><a href="../doxygen/html/classqx_1_1_qx_invalid_value.html"
target="_blank">qx::QxInvalidValue</a> : each item into this collection is type of
<i>qx::QxInvalidValue</i> and contains an error message (description to explain why the instance
is not valid).
</li>
</ul>
<b>QxValidator</b> module manages automatically class inheritance : each constraint defined into a
base class is checked during validation process of a derived class.<br>
<br>
Here is an example using <b>QxValidator</b> module with a '<i>person</i>' class :<br>
<br>
* '<i>person.h</i>' file :<br>
<table border="1" bgcolor="#FFFFFF">
<col>
<tbody>
<tr>
<td>
<pre><span class="pre">#ifndef _CLASS_PERSON_H_
#define _CLASS_PERSON_H_
</span><span class="keyword">
class</span> person<span class="operator">
{</span><span class="keyword">
public</span><span class="operator">:</span><span class="keyword">
enum</span> sex<span class="operator"> {</span> male<span class="operator">,</span> female<span class="operator">,</span> unknown<span class="operator"> };</span><span class="type">
long</span> _id<span class="operator">;</span>
QString _firstName<span class="operator">;</span>
QString _lastName<span class="operator">;</span>
QDateTime _birthDate<span class="operator">;</span>
sex _sex<span class="operator">;</span>
person<span class="operator">() :</span> _id<span class="operator">(</span><span class="int">0</span><span class="operator">),</span> _sex<span class="operator">(</span>unknown<span class="operator">) { ; }</span>
person<span class="operator">(</span><span class="type">long</span> id<span class="operator">) :</span> _id<span class="operator">(</span>id<span class="operator">),</span> _sex<span class="operator">(</span>unknown<span class="operator">) { ; }</span><span class="keyword">
virtual</span><span class="operator"> ~</span>person<span class="operator">() { ; }</span><span class="keyword">
private</span><span class="operator">:</span><span class="type">
void</span> isValid<span class="operator">(</span>qx<span class="operator">::</span>QxInvalidValueX<span class="operator"> &amp;</span> invalidValues<span class="operator">);
};</span>
QX_REGISTER_HPP_MY_EXE<span class="operator">(</span>person<span class="operator">,</span> qx<span class="operator">::</span>trait<span class="operator">::</span>no_base_class_defined<span class="operator">,</span><span class="int"> 0</span><span class="operator">)</span><span class="pre">
#endif // _CLASS_PERSON_H_</span></pre>
</td>
</tr>
</tbody>
</table>
<br>
* '<i>person.cpp</i>' file :<br>
<table border="1" bgcolor="#FFFFFF">
<col>
<tbody>
<tr>
<td>
<pre><span class="pre">#include "../include/precompiled.h"
#include "../include/person.h"
#include "../include/global_validator.h"
#include &lt;QxOrm_Impl.h&gt;
</span>
QX_REGISTER_CPP_MY_EXE<span class="operator">(</span>person<span class="operator">)</span><span class="keyword">
namespace</span> qx<span class="operator"> {</span><span class="keyword">
template</span><span class="operator"> &lt;&gt;</span><span class="type"> void</span> register_class<span class="operator">(</span>QxClass<span class="operator">&lt;</span>person<span class="operator">&gt; &amp;</span> t<span class="operator">)
{</span>
t<span class="operator">.</span>id<span class="operator">(&amp;</span> person<span class="operator">::</span>_id<span class="operator">,</span><span class="string"> "id"</span><span class="operator">);</span>
t<span class="operator">.</span>data<span class="operator">(&amp;</span> person<span class="operator">::</span>_firstName<span class="operator">,</span><span class="string"> "firstName"</span><span class="operator">);</span>
t<span class="operator">.</span>data<span class="operator">(&amp;</span> person<span class="operator">::</span>_lastName<span class="operator">,</span><span class="string"> "lastName"</span><span class="operator">);</span>
t<span class="operator">.</span>data<span class="operator">(&amp;</span> person<span class="operator">::</span>_birthDate<span class="operator">,</span><span class="string"> "birthDate"</span><span class="operator">);</span>
t<span class="operator">.</span>data<span class="operator">(&amp;</span> person<span class="operator">::</span>_sex<span class="operator">,</span><span class="string"> "sex"</span><span class="operator">);</span>
QxValidatorX<span class="operator">&lt;</span>person<span class="operator">&gt; *</span> pAllValidator<span class="operator"> =</span> t<span class="operator">.</span>getAllValidator<span class="operator">();</span>
pAllValidator<span class="operator">-&gt;</span>add_NotEmpty<span class="operator">(</span><span class="string">"firstName"</span><span class="operator">);</span>
pAllValidator<span class="operator">-&gt;</span>add_NotEmpty<span class="operator">(</span><span class="string">"lastName"</span><span class="operator">,</span><span class="string"> "a person must have a lastname"</span><span class="operator">);</span>
pAllValidator<span class="operator">-&gt;</span>add_CustomValidator<span class="operator">(&amp;</span> person<span class="operator">::</span>isValid<span class="operator">);</span>
pAllValidator<span class="operator">-&gt;</span>add_CustomValidator_QVariant<span class="operator">(&amp;</span> validateFirstName<span class="operator">,</span><span class="string"> "firstName"</span><span class="operator">);</span>
pAllValidator<span class="operator">-&gt;</span>add_CustomValidator_DataType<span class="operator">&lt;</span>QDateTime<span class="operator">&gt;(&amp;</span> validateDateTime<span class="operator">,</span><span class="string"> "birthDate"</span><span class="operator">);
}}</span><span class="type">
void</span> person<span class="operator">::</span>isValid<span class="operator">(</span>qx<span class="operator">::</span>QxInvalidValueX<span class="operator"> &amp;</span> invalidValues<span class="operator">)
{</span><span class="comment">
// This method is called automatically by 'QxValidator' module (validator engine of QxOrm library) :
// - when you try to insert or update using 'qx::dao::xxx' functions
// - when you call 'qx::validate()' function
// For registration, see 'pAllValidator->add_CustomValidator(& person::isValid);' into 'qx::register_class' function
// Here, you can verify some values of your instance
// If a value is not valid, you must add an invalid value into the collection 'invalidValues'
// For example, if we want to check property '_sex' of a person :
</span><span class="flow"> if</span><span class="operator"> ((</span>_sex<span class="operator"> !=</span> male<span class="operator">) &amp;&amp; (</span>_sex<span class="operator"> !=</span> female<span class="operator">))
{</span> invalidValues<span class="operator">.</span>insert<span class="operator">(</span><span class="string">"person sex must be defined : male or female"</span><span class="operator">); }
}</span></pre>
</td>
</tr>
</tbody>
</table>
<br>
* '<i>global_validator.h</i>' file :<br>
<table border="1" bgcolor="#FFFFFF">
<col>
<tbody>
<tr>
<td>
<pre><span class="comment">// Example of global functions 'validateFirstName' and 'validateDateTime' used by 'QxValidator' module
// Those functions will be called automatically by validator engine of QxOrm library :
// - when you try to insert or update using 'qx::dao::xxx' functions
// - when you call 'qx::validate()' function
</span><span class="type">
void</span> validateFirstName<span class="operator">(</span><span class="keyword">const</span> QVariant<span class="operator"> &amp;</span> value<span class="operator">,</span><span class="keyword"> const</span> qx<span class="operator">::</span>IxValidator<span class="operator"> *</span> validator<span class="operator">,</span> qx<span class="operator">::</span>QxInvalidValueX<span class="operator"> &amp;</span> invalidValues<span class="operator">)
{</span><span class="comment">
// Here you can test the value (converted to QVariant type)
// If an invalid value is detected, just add a message into 'invalidValues' collection
// For example, if the value must be never equal to "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">"value must not be equal to 'admin'"</span><span class="operator">); }
}</span><span class="type">
void</span> validateDateTime<span class="operator">(</span><span class="keyword">const</span> QDateTime<span class="operator"> &amp;</span> value<span class="operator">,</span><span class="keyword"> const</span> qx<span class="operator">::</span>IxValidator<span class="operator"> *</span> validator<span class="operator">,</span> qx<span class="operator">::</span>QxInvalidValueX<span class="operator"> &amp;</span> invalidValues<span class="operator">)
{</span><span class="comment">
// Here you can test the value (with its real type, in this example, the data-member is a 'QDateTime' type)
// If an invalid value is detected, just add a message into 'invalidValues' collection
// For example, if the date-time must be valid :
</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">"date-time value must not be empty and must be valid"</span><span class="operator">); }
}</span></pre>
</td>
</tr>
</tbody>
</table>
<br>
* '<i>main.cpp</i>' file :<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>
During program execution of this code, '<i>personValidate</i>' instance is not valid :
'<i>invalidValues</i>' collection contains 4 items :<br>
- "<i>property 'firstName' must not be empty</i>" ;<br>
- "<i>person sex must be defined : male or female</i>" ;<br>
- "<i>value must not be equal to 'admin'</i>" ;<br>
- "<i>date-time value must not be empty and must be valid</i>".<br>
<br>
<b>QxValidator</b> module provides some built-in constraints, which cover most of the basic data
checks.<br>
As we'll see later, you're not limited to them, you can literally in a minute write your own
constraints :
<ul>
<li><i>add_NotNull()</i> : checks if the value is not null ;</li>
<li><i>add_NotEmpty()</i> : checks if the string is not empty ;</li>
<li><i>add_MinValue()</i> : checks if the value is more than or equals to min ;</li>
<li><i>add_MaxValue()</i> : checks if the value is less than or equals to max ;</li>
<li><i>add_Range()</i> : checks if the value is between Min and Max (included) ;</li>
<li><i>add_MinDecimal()</i> : checks if the decimal value is more than or equals to min ;</li>
<li><i>add_MaxDecimal()</i> : checks if the decimal value is less than or equals to max ;</li>
<li><i>add_RangeDecimal()</i> : checks if the decimal value is between Min and Max (included) ;</li>
<li><i>add_MinLength()</i> : checks if the string length is more than or equals to min ;</li>
<li><i>add_MaxLength()</i> : checks if the string length is less than or equals to max ;</li>
<li><i>add_Size()</i> : checks if the string length is between the min-max range ;</li>
<li><i>add_DatePast()</i> : checks if the date is in the past ;</li>
<li><i>add_DateFuture()</i> : checks if the date is in the future ;</li>
<li><i>add_RegExp()</i> : checks if the property matches the regular expression given a match flag ;
</li>
<li><i>add_EMail()</i> : checks whether the string conforms to the email address specification.</li>
</ul>
Like '<i>person</i>' class example, it's possible to define a custom validator : it's a function or a
class method called automatically by <b>QxValidator</b> module to validate a property or an instance
of class.<br>
There are 3 kinds of custom validator :
<ul>
<li><i>add_CustomValidator()</i> : class method, method signature must be "<i>void
my_class::my_method(qx::QxInvalidValueX &)</i>" ;</li>
<li><i>add_CustomValidator_QVariant()</i> : global function with <i>QVariant</i> type (the property
is converted into <i>QVariant</i> type), function signature must be "<i>void my_validator(const
QVariant &, const qx::IxValidator *, qx::QxInvalidValueX &)</i>" ;</li>
<li><i>add_CustomValidator_DataType()</i> : global function with real type, function signature must
be "<i>void my_validator(const T &, const qx::IxValidator *, qx::QxInvalidValueX &)</i>" ;</li>
</ul>
<b>Note :</b> each validator can be associated with a group (optional parameter for each function
<i>add_XXX()</i> of <i>qx::IxValidatorX</i> class).<br>
So it's possible to create a context validation during program execution : for example, a person from
IHM A can have different validation rules than a person from IHM B.<br>
To execute a validation process by group (for example "<i>myGroup</i>"), you have to call the
following function : "<i>qx::QxInvalidValueX invalidValues = qx::validate(personValidate,
"myGroup");</i>".<br>
<br>
<b>Other note :</b> <b>QxValidator</b> module provides default messages when a constraint violation is
detected.<br>
It's possible to modify those default messages (for example, a traduction) using the following
collection : "<i>QHash<QString, QString> * lstMessage = QxClassX::getAllValidatorMessage();</i>".<br>
For example : "<i>lstMessage->insert("min_value", "la valeur '%NAME%' doit <20>tre inf<6E>rieure ou <20>gale <20>
'%CONSTRAINT%'");</i>".<br>
<i>%NAME%</i> and <i>%CONSTRAINT%</i> fields will be automatically replaced by the good value.<br>
To modify a message for a specific validator (and not globally), you have to use the optional
parameter provided by each function <i>add_XXX()</i> of <i>qx::IxValidatorX</i> class.<br>
</td>
</tr>
</tbody>
</table>
<br><br>
<a name="faq_260"><u><b>How to use <i>qx::IxPersistable</i> interface ?</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">
<i><a href="../doxygen/html/classqx_1_1_ix_persistable.html" target="_blank">qx::IxPersistable</a></i>
interface (or abstract class) provides only pure virtual methods.<br>
Using <i>qx::IxPersistable</i>, you will have a common base class to call all persistents functions
without knowing the real type of current instance (polymorphism concept).<br>
QxOrm library doesn't force developers to work with a base class to register a persistent type into
QxOrm context, however it's sometimes useful to have an interface to write some generic
algorithms.<br>
<br>
<i>qx::IxPersistable</i> class provides following virtual methods (for more details about those
methods, goto <a href="../doxygen/index.html" target="_blank">QxOrm library online class
documentation</a>) :<br>
<br>
<div style="width:900px; height:290px; overflow:auto; background-color:white">
<pre><span class="keyword">virtual</span><span class="type"> long</span> qxCount<span class="operator">(</span><span class="keyword">const</span> qx<span class="operator">::</span>QxSqlQuery<span class="operator"> &amp;</span> query<span class="operator"> =</span> qx<span class="operator">::</span>QxSqlQuery<span class="operator">(),</span> QSqlDatabase<span class="operator"> *</span> pDatabase<span class="operator"> =</span> NULL<span class="operator">);</span><span class="keyword">
virtual</span> QSqlError qxFetchById<span class="operator">(</span><span class="keyword">const</span> QVariant<span class="operator"> &amp;</span> id<span class="operator"> =</span> QVariant<span class="operator">(),</span><span class="keyword"> const</span> QStringList<span class="operator"> &amp;</span> columns<span class="operator"> =</span> QStringList<span class="operator">(),</span><span class="keyword"> const</span> QStringList<span class="operator"> &amp;</span> relation<span class="operator"> =</span> QStringList<span class="operator">(),</span> QSqlDatabase<span class="operator"> *</span> pDatabase<span class="operator"> =</span> NULL<span class="operator">);</span><span class="keyword">
virtual</span> QSqlError qxFetchAll<span class="operator">(</span>qx<span class="operator">::</span>IxCollection<span class="operator"> &amp;</span> list<span class="operator">,</span><span class="keyword"> const</span> QStringList<span class="operator"> &amp;</span> columns<span class="operator"> =</span> QStringList<span class="operator">(),</span><span class="keyword"> const</span> QStringList<span class="operator"> &amp;</span> relation<span class="operator"> =</span> QStringList<span class="operator">(),</span> QSqlDatabase<span class="operator"> *</span> pDatabase<span class="operator"> =</span> NULL<span class="operator">);</span><span class="keyword">
virtual</span> QSqlError qxFetchByQuery<span class="operator">(</span><span class="keyword">const</span> qx<span class="operator">::</span>QxSqlQuery<span class="operator"> &amp;</span> query<span class="operator">,</span> qx<span class="operator">::</span>IxCollection<span class="operator"> &amp;</span> list<span class="operator">,</span><span class="keyword"> const</span> QStringList<span class="operator"> &amp;</span> columns<span class="operator"> =</span> QStringList<span class="operator">(),</span><span class="keyword"> const</span> QStringList<span class="operator"> &amp;</span> relation<span class="operator"> =</span> QStringList<span class="operator">(),</span> QSqlDatabase<span class="operator"> *</span> pDatabase<span class="operator"> =</span> NULL<span class="operator">);</span><span class="keyword">
virtual</span> QSqlError qxInsert<span class="operator">(</span><span class="keyword">const</span> QStringList<span class="operator"> &amp;</span> relation<span class="operator"> =</span> QStringList<span class="operator">(),</span> QSqlDatabase<span class="operator"> *</span> pDatabase<span class="operator"> =</span> NULL<span class="operator">);</span><span class="keyword">
virtual</span> QSqlError qxUpdate<span class="operator">(</span><span class="keyword">const</span> qx<span class="operator">::</span>QxSqlQuery<span class="operator"> &amp;</span> query<span class="operator"> =</span> qx<span class="operator">::</span>QxSqlQuery<span class="operator">(),</span><span class="keyword"> const</span> QStringList<span class="operator"> &amp;</span> columns<span class="operator"> =</span> QStringList<span class="operator">(),</span><span class="keyword"> const</span> QStringList<span class="operator"> &amp;</span> relation<span class="operator"> =</span> QStringList<span class="operator">(),</span> QSqlDatabase<span class="operator"> *</span> pDatabase<span class="operator"> =</span> NULL<span class="operator">);</span><span class="keyword">
virtual</span> QSqlError qxSave<span class="operator">(</span><span class="keyword">const</span> QStringList<span class="operator"> &amp;</span> relation<span class="operator"> =</span> QStringList<span class="operator">(),</span> QSqlDatabase<span class="operator"> *</span> pDatabase<span class="operator"> =</span> NULL<span class="operator">);</span><span class="keyword">
virtual</span> QSqlError qxDeleteById<span class="operator">(</span><span class="keyword">const</span> QVariant<span class="operator"> &amp;</span> id<span class="operator"> =</span> QVariant<span class="operator">(),</span> QSqlDatabase<span class="operator"> *</span> pDatabase<span class="operator"> =</span> NULL<span class="operator">);</span><span class="keyword">
virtual</span> QSqlError qxDeleteAll<span class="operator">(</span>QSqlDatabase<span class="operator"> *</span> pDatabase<span class="operator"> =</span> NULL<span class="operator">);</span><span class="keyword">
virtual</span> QSqlError qxDeleteByQuery<span class="operator">(</span><span class="keyword">const</span> qx<span class="operator">::</span>QxSqlQuery<span class="operator"> &amp;</span> query<span class="operator">,</span> QSqlDatabase<span class="operator"> *</span> pDatabase<span class="operator"> =</span> NULL<span class="operator">);</span><span class="keyword">
virtual</span> QSqlError qxDestroyById<span class="operator">(</span><span class="keyword">const</span> QVariant<span class="operator"> &amp;</span> id<span class="operator"> =</span> QVariant<span class="operator">(),</span> QSqlDatabase<span class="operator"> *</span> pDatabase<span class="operator"> =</span> NULL<span class="operator">);</span><span class="keyword">
virtual</span> QSqlError qxDestroyAll<span class="operator">(</span>QSqlDatabase<span class="operator"> *</span> pDatabase<span class="operator"> =</span> NULL<span class="operator">);</span><span class="keyword">
virtual</span> QSqlError qxDestroyByQuery<span class="operator">(</span><span class="keyword">const</span> qx<span class="operator">::</span>QxSqlQuery<span class="operator"> &amp;</span> query<span class="operator">,</span> QSqlDatabase<span class="operator"> *</span> pDatabase<span class="operator"> =</span> NULL<span class="operator">);</span><span class="keyword">
virtual</span> qx_bool qxExist<span class="operator">(</span><span class="keyword">const</span> QVariant<span class="operator"> &amp;</span> id<span class="operator"> =</span> QVariant<span class="operator">(),</span> QSqlDatabase<span class="operator"> *</span> pDatabase<span class="operator"> =</span> NULL<span class="operator">);</span><span class="keyword">
virtual</span> qx<span class="operator">::</span>QxInvalidValueX qxValidate<span class="operator">(</span><span class="keyword">const</span> QStringList<span class="operator"> &amp;</span> groups<span class="operator"> =</span> QStringList<span class="operator">());</span><span class="keyword">
virtual</span> qx<span class="operator">::</span>IxPersistableCollection_ptr qxNewPersistableCollection<span class="operator">()</span><span class="keyword"> const</span><span class="operator">;</span><span class="keyword">
virtual</span> qx<span class="operator">::</span>IxClass<span class="operator"> *</span> qxClass<span class="operator">()</span><span class="keyword"> const</span><span class="operator">;</span></pre>
</div>
<br>
For example, working with a list of <i>qx::IxPersistable</i> pointers, it's possible to save all items
into many tables of database, like this :<br>
<br>
<table border="1" bgcolor="#FFFFFF">
<col>
<tbody>
<tr>
<td>
<pre>QList<span class="operator">&lt;</span>qx<span class="operator">::</span>IxPersistable<span class="operator"> *&gt;</span> lst<span class="operator"> = ...;</span>
foreach<span class="operator">(</span>qx<span class="operator">::</span>IxPersistable<span class="operator"> *</span> p<span class="operator">,</span> lst<span class="operator">)
{</span>
QSqlError daoError<span class="operator"> =</span> p<span class="operator">-&gt;</span>qxSave<span class="operator">();</span><span class="flow">
if</span><span class="operator"> (</span>daoError<span class="operator">.</span>isValid<span class="operator">()) {</span><span class="comment"> /* an error occured */</span><span class="operator"> }</span><span class="comment">
// etc...
</span><span class="operator">}</span></pre>
</td>
</tr>
</tbody>
</table>
<br>
To implement <i>qx::IxPersistable</i> interface, it's necessary to :
<ul>
<li>inherit persistent class from <i>qx::IxPersistable</i> ;</li>
<li>into class definition (<i>myClass.h</i> for example), add <i>QX_PERSISTABLE_HPP(myClass)</i>
macro ;</li>
<li>into class implementation (<i>myClass.cpp</i> for example), add
<i>QX_PERSISTABLE_CPP(myClass)</i> macro.
</li>
</ul>
For example, to implement <i>qx::IxPersistable</i> interface for <a
href="./tutorial.html#tuto_6"><i>author</i></a> class from <i>qxBlog</i> tutorial, you have to write
:<br>
<br>
<table border="1" bgcolor="#FFFFFF">
<col>
<tbody>
<tr>
<td title="author.h">
<pre><span class="pre">#ifndef _QX_BLOG_AUTHOR_H_
#define _QX_BLOG_AUTHOR_H_
</span><span class="keyword">
class</span> blog<span class="operator">;</span><span class="keyword">
class</span> QX_BLOG_DLL_EXPORT author : <font style="background-color:yellow"><b>public qx::IxPersistable</b></font><span class="operator">
{</span>
<font style="background-color:yellow"><b>QX_PERSISTABLE_HPP(author)</b></font>
<span class="keyword">public</span><span class="operator">:</span><span class="comment">
// -- typedef
</span><span class="keyword"> typedef</span> boost<span class="operator">::</span>shared_ptr<span class="operator">&lt;</span>blog<span class="operator">&gt;</span> blog_ptr<span class="operator">;</span><span class="keyword">
typedef</span> std<span class="operator">::</span>vector<span class="operator">&lt;</span>blog_ptr<span class="operator">&gt;</span> list_blog<span class="operator">;</span><span class="comment">
// -- enum
</span><span class="keyword"> enum</span> enum_sex<span class="operator"> {</span> male<span class="operator">,</span> female<span class="operator">,</span> unknown<span class="operator"> };</span><span class="comment">
// -- properties
</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">
// -- contructor, virtual destructor
</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">
// -- methods
</span><span class="type"> int</span> age<span class="operator">()</span><span class="keyword"> const</span><span class="operator">;
};</span>
QX_REGISTER_PRIMARY_KEY<span class="operator">(</span>author<span class="operator">,</span> QString<span class="operator">)</span>
QX_REGISTER_HPP_QX_BLOG<span class="operator">(</span>author<span class="operator">,</span> qx<span class="operator">::</span>trait<span class="operator">::</span>no_base_class_defined<span class="operator">,</span><span class="int"> 0</span><span class="operator">)</span><span class="keyword">
typedef</span> boost<span class="operator">::</span>shared_ptr<span class="operator">&lt;</span>author<span class="operator">&gt;</span> author_ptr<span class="operator">;</span><span class="keyword">
typedef</span> qx<span class="operator">::</span>QxCollection<span class="operator">&lt;</span>QString<span class="operator">,</span> author_ptr<span class="operator">&gt;</span> list_author<span class="operator">;</span><span class="pre">
#endif <span class="comment">// _QX_BLOG_AUTHOR_H_</span>
</span></pre>
</td>
</tr>
</tbody>
</table>
<br>
<table border="1" bgcolor="#FFFFFF">
<col>
<tbody>
<tr>
<td title="author.cpp">
<pre><span class="pre">#include <span class="string">"../include/precompiled.h"</span>
#include <span class="string">"../include/author.h"</span>
#include <span class="string">"../include/blog.h"</span>
#include <span class="string">&lt;QxOrm_Impl.h&gt;</span>
</span>
QX_REGISTER_CPP_QX_BLOG<span class="operator">(</span>author<span class="operator">)</span>
<font style="background-color:yellow"><b>QX_PERSISTABLE_CPP(author)</b></font>
<span class="keyword">namespace</span> qx<span class="operator"> {</span><span class="keyword">
template</span><span class="operator"> &lt;&gt;</span><span class="type"> void</span> register_class<span class="operator">(</span>QxClass<span class="operator">&lt;</span>author<span class="operator">&gt; &amp;</span> t<span class="operator">)
{</span>
t<span class="operator">.</span>id<span class="operator">(&amp;</span> author<span class="operator">::</span>m_id<span class="operator">,</span><span class="string"> "author_id"</span><span class="operator">);</span>
t<span class="operator">.</span>data<span class="operator">(&amp;</span> author<span class="operator">::</span>m_name<span class="operator">,</span><span class="string"> "name"</span><span class="operator">);</span>
t<span class="operator">.</span>data<span class="operator">(&amp;</span> author<span class="operator">::</span>m_birthdate<span class="operator">,</span><span class="string"> "birthdate"</span><span class="operator">);</span>
t<span class="operator">.</span>data<span class="operator">(&amp;</span> author<span class="operator">::</span>m_sex<span class="operator">,</span><span class="string"> "sex"</span><span class="operator">);</span>
t<span class="operator">.</span>relationOneToMany<span class="operator">(&amp;</span> author<span class="operator">::</span>m_blogX<span class="operator">,</span><span class="string"> "list_blog"</span><span class="operator">,</span><span class="string"> "author_id"</span><span class="operator">);</span>
t<span class="operator">.</span>fct_0<span class="operator">&lt;</span><span class="type">int</span><span class="operator">&gt;(&amp;</span> author<span class="operator">::</span>age<span class="operator">,</span><span class="string"> "age"</span><span class="operator">);
}}</span><span class="type">
int</span> author<span class="operator">::</span>age<span class="operator">()</span><span class="keyword"> const</span><span class="operator">
{</span><span class="flow">
if</span><span class="operator"> (!</span> m_birthdate<span class="operator">.</span>isValid<span class="operator">()) {</span><span class="flow"> return</span><span class="operator"> -</span><span class="int">1</span><span class="operator">; }</span><span class="flow">
return</span><span class="operator"> (</span>QDate<span class="operator">::</span>currentDate<span class="operator">().</span>year<span class="operator">() -</span> m_birthdate<span class="operator">.</span>year<span class="operator">());
}</span>
</pre>
</td>
</tr>
</tbody>
</table>
<br>
<b>Note :</b> project test from <i>./test/qxDllSample/dll1/</i> directory provides a kind of 'super
base class' : <i>qx::QxPersistable</i> class implements <i><a
href="../doxygen/html/classqx_1_1_ix_persistable.html" target="_blank">qx::IxPersistable</a></i>
interface and inherits from <i>QObject</i>.<br>
So <i>SIGNAL-SLOT</i> concept from Qt library can be used with this class and could be an interesting
way to use QxOrm <a href="./faq.html#faq_130"><i>triggers</i></a>.<br>
<i>qx::QxPersistable</i> class provides also some virtual methods to override to manage for example
data validation process from <a href="./faq.html#faq_250"><i>QxValidator</i></a> module.<br>
For information, <i>qx::QxPersistable</i> class is not a part of QxOrm library, but you can copy-past
it into your own project to use all its features :
<ul>
<li>access to <a href="./resource/qx_persistable_hpp.html"
target="_blank"><i>QxPersistable.hpp</i></a> file ;</li>
<li>access to <a href="./resource/qx_persistable_cpp.html"
target="_blank"><i>QxPersistable.cpp</i></a> file.</li>
</ul>
</td>
</tr>
</tbody>
</table>
<br><br>
<a name="faq_270"><u><b>How to use relationship engine to fetch datas from many 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">
QxOrm library supports 4 kind of relationships to link C++ classes registered in QxOrm context :
<i>one-to-one</i>, <i>one-to-many</i>, <i>many-to-one</i> and <i>many-to-many</i>.<br>
For more details to define relationships, you can take a look at <a href="./tutorial.html"
target="_blank">qxBlog tutorial</a>.<br>
We will explain here how to fetch datas from many tables (<a
href="../doxygen/html/group___qx_dao.html" target="_blank">QxDao</a> module, functions of <a
href="../doxygen/html/namespaceqx_1_1dao.html" target="_blank">qx::dao</a> namespace) :
<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> and <a
href="../doxygen/html/namespaceqx_1_1dao.html" target="_blank">fetch_by_query</a> : fetch datas
from only 1 table from database (<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>
and <a href="../doxygen/html/namespaceqx_1_1dao.html"
target="_blank">fetch_by_query_with_all_relation</a> : fetch datas from 1 table + all tables
linked (<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> and
<a href="../doxygen/html/namespaceqx_1_1dao.html" target="_blank">fetch_by_query_with_relation</a>
: same as above (<i>eager fetch</i>) with possibility to indicate relationships to fetch on many
levels.
</li>
</ul>
The first parameter of <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> and <a href="../doxygen/html/namespaceqx_1_1dao.html"
target="_blank">fetch_by_query_with_relation</a> functions is the list of relationships to
fetch.<br>
This list of relationships can contain those items :
<ul>
<li>relation key : each relation is associated to a key defined into
<i>qx::register_class&lt;T&gt;</i> setting function ;
</li>
<li>"<i>*</i>" keyword means "<i>fetch all relationships defined into
<i>qx::register_class&lt;T&gt;</i> function (1 level of relationships)</i>" ;</li>
<li>"<i>-></i>" keyword means "<i>LEFT OUTER JOIN</i>" join type between 2 tables ;</li>
<li>"<i>>></i>" keyword means "<i>INNER JOIN</i>" join type between 2 tables.</li>
</ul>
<b>Note :</b> using "*" keyword to indicate "<i>fetch all relationships defined into
<i>qx::register_class&lt;T&gt;</i> function</i>", those calls are similar :
<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>Example :</b> from qxBlog tutorial, it's possible to fetch all those datas with only 1 query :<br>
<br>
<b>1-</b> fetch a <i>blog</i> and its <i>author</i> ;<br>
<b>2-</b> for the <i>author</i> fetched, fetch all <i>blog</i> he wrote ;<br>
<b>3-</b> for each <i>blog</i> written by <i>author</i> fetched, fetch all <i>comment</i>
associated.<br>
<br>
<table border="1" bgcolor="#FFFFFF">
<col>
<tbody>
<tr>
<td title="complex fetch with relationships">
<pre>blog_ptr my_blog<span class="operator"> =</span> blog_ptr<span class="operator">(</span><span class="keyword">new</span> blog<span class="operator">(</span><span class="int">10</span><span class="operator">));</span>
QSqlError daoError<span class="operator"> =</span> qx<span class="operator">::</span>dao<span class="operator">::</span>fetch_by_id_with_relation<span class="operator">(</span><span class="string">"author_id-&gt;list_blog-&gt;list_comment"</span><span class="operator">,</span> my_blog<span class="operator">);</span></pre>
</td>
</tr>
</tbody>
</table>
<br>
This code builds the following SQL query :
<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>Another example :</b> it's also possible to create a list of relationships to fetch, like this
:<br>
<br>
<table border="1" bgcolor="#FFFFFF">
<col>
<tbody>
<tr>
<td title="complex fetch with relationships">
<pre>blog_ptr my_blog<span class="operator"> =</span> blog_ptr<span class="operator">(</span><span class="keyword">new</span> blog<span class="operator">(</span><span class="int">10</span><span class="operator">));</span>
QStringList relation<span class="operator">;</span>
relation<span class="operator"> &lt;&lt;</span><span class="string"> "author_id-&gt;list_blog-&gt;list_comment"</span><span class="operator">;</span>
relation<span class="operator"> &lt;&lt;</span><span class="string"> "author_id-&gt;list_blog-&gt;list_category"</span><span class="operator">;</span>
relation<span class="operator"> &lt;&lt;</span><span class="string"> "list_comment"</span><span class="operator">;</span>
relation<span class="operator"> &lt;&lt;</span><span class="string"> "list_category"</span><span class="operator">;</span>
QSqlError daoError<span class="operator"> =</span> qx<span class="operator">::</span>dao<span class="operator">::</span>fetch_by_id_with_relation<span class="operator">(</span>relation<span class="operator">,</span> my_blog<span class="operator">);</span></pre>
</td>
</tr>
</tbody>
</table>
<br>
This code builds the following SQL query :
<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>Another example :</b> to fetch all relationships per level, "*" keyword must be used.<br>
So to fetch all relationships on 3 levels, we can write :<br>
<br>
<table border="1" bgcolor="#FFFFFF">
<col>
<tbody>
<tr>
<td title="complex fetch with relationships">
<pre>blog_ptr my_blog<span class="operator"> =</span> blog_ptr<span class="operator">(</span><span class="keyword">new</span> blog<span class="operator">(</span><span class="int">10</span><span class="operator">));</span>
QSqlError daoError<span class="operator"> =</span> qx<span class="operator">::</span>dao<span class="operator">::</span>fetch_by_id_with_relation<span class="operator">(</span><span class="string">"*-&gt;*-&gt;*"</span><span class="operator">,</span> my_blog<span class="operator">);</span></pre>
</td>
</tr>
</tbody>
</table>
<br>
This code builds the following SQL query :
<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>How to execute a stored procedure or a custom SQL query ?</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">
QxOrm library provides 2 functions to execute a stored procedure or a custom SQL query :
<ul>
<li><a href="../doxygen/html/namespaceqx_1_1dao.html"
target="_blank">qx::dao::execute_query&lt;T&gt;()</a></li>
<li><a href="../doxygen/html/namespaceqx_1_1dao.html" target="_blank">qx::dao::call_query()</a></li>
</ul>
The first parameter of those functions, of <i><a href="../doxygen/html/classqx_1_1_qx_sql_query.html"
target="_blank">qx::QxSqlQuery</a></i> type (or <i>qx_query</i>), contains the stored procedure or
the custom SQL query to execute.<br>
For more informations about <i><a href="../doxygen/html/classqx_1_1_qx_sql_query.html"
target="_blank">qx::QxSqlQuery</a></i> class, goto here : <a href="./faq.html#faq_210">How to
build a query without writing SQL with the class <i>qx::QxSqlQuery</i> ?</a><br>
<br>
<a href="../doxygen/html/namespaceqx_1_1dao.html"
target="_blank">qx::dao::execute_query&lt;T&gt;()</a> function is a <i>template</i> function : T
type must be registered in QxOrm context (<i>qx::register_class&lt;T&gt;</i> function).<br>
All datas returned by the stored procedure or the custom SQL query which could be associated with
members of the C++ class (of T type) will be fetched automatically.<br>
An automatic search is done on the name of each fields returned by the query.<br>
Here is an example from qxBlog project of QxOrm package :<br>
<br>
<table border="1" bgcolor="#FFFFFF">
<col>
<tbody>
<tr>
<td>
<pre><span class="comment">// Call a custom SQL query or a stored procedure and fetch automatically properties (with a collection of items)
</span>qx_query testStoredProcBis<span class="operator">(</span><span class="string">"SELECT * FROM author"</span><span class="operator">);</span>
daoError<span class="operator"> =</span> qx<span class="operator">::</span>dao<span class="operator">::</span>execute_query<span class="operator">(</span>testStoredProcBis<span class="operator">,</span> authorX<span class="operator">);</span>
qAssert<span class="operator">(!</span> daoError<span class="operator">.</span>isValid<span class="operator">());</span> qAssert<span class="operator">(</span>authorX<span class="operator">.</span>count<span class="operator">() &gt;</span><span class="int"> 0</span><span class="operator">);</span>
qx<span class="operator">::</span>dump<span class="operator">(</span>authorX<span class="operator">);</span></pre>
</td>
</tr>
</tbody>
</table>
<br><br>
<a href="../doxygen/html/namespaceqx_1_1dao.html" target="_blank">qx::dao::call_query()</a> function
is not a <i>template</i> function : you have to iterate over each result using <i><a
href="../doxygen/html/classqx_1_1_qx_sql_query.html" target="_blank">qx::QxSqlQuery</a></i> class
(or <i>qx_query</i>).<br>
To get an output value parameter (must be pass as <i>QSql::Out</i> or <i>QSql::InOut</i>) returned by
a stored procedure, just call the following method : <i>QVariant qx::QxSqlQuery::boundValue(const
QString & sKey) const;</i>.<br>
<br>
To iterate over all resultset, just use the following methods :<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>
Here is an example using <a href="../doxygen/html/namespaceqx_1_1dao.html"
target="_blank">qx::dao::call_query()</a> function :<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>How to use <i>qx::QxDaoAsync</i> class to execute queries in asynchronous way
(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">
Sometimes, it's necessary to execute some queries to database in asynchronous way (multi-thread), for
example to avoid to freeze a GUI if a query is too long to execute.<br>
To make easier to work with asynchronous queries, QxOrm library provides <i><a
href="../doxygen/html/classqx_1_1_qx_dao_async.html" target="_blank">qx::QxDaoAsync</a></i>
class.<br>
This class executes a query in another thread and returns the <i>queryFinished()</i> <i>SIGNAL</i>
when query is terminated.<br>
To use <i><a href="../doxygen/html/classqx_1_1_qx_dao_async.html"
target="_blank">qx::QxDaoAsync</a></i> class, you just have to :
<ul>
<li>be careful to work only with classes implementing <i><a
href="../doxygen/html/classqx_1_1_ix_persistable.html"
target="_blank">qx::IxPersistable</a></i> interface ;</li>
<li>create an instance of <i>qx::QxDaoAsync</i> type (for example, a property of a <i>QWidget</i>
derived class) ;</li>
<li>connect a <i>SLOT</i> to the <i>qx::QxDaoAsync::queryFinished()</i> <i>SIGNAL</i> (for example,
a <i>SLOT</i> of a <i>QWidget</i> derived class) ;</li>
<li>run a query using one of <i>qx::QxDaoAsync::asyncXXXX()</i> methods.</li>
</ul>
Here is an example with a class called <i>MyWidget</i> :<br>
<br>
<table border="1" bgcolor="#FFFFFF">
<col>
<tbody>
<tr>
<td>
<pre><span class="keyword">class</span> MyWidget<span class="operator"> :</span><span class="keyword"> public</span> QWidget<span class="operator">
{</span> Q_OBJECT<span class="comment">
//...
</span> qx<span class="operator">::</span>QxDaoAsync m_daoAsync<span class="operator">;</span><span class="comment">
//...
</span>Q_SLOTS<span class="operator">:</span><span class="type">
void</span> onQueryFinished<span class="operator">(</span><span class="keyword">const</span> QSqlError<span class="operator"> &amp;</span> daoError<span class="operator">,</span> qx<span class="operator">::</span>dao<span class="operator">::</span>detail<span class="operator">::</span>QxDaoAsyncParams_ptr pDaoParams<span class="operator">);</span><span class="comment">
//...
</span><span class="operator">};</span></pre>
</td>
</tr>
</tbody>
</table>
<br>
And here is the implementation of <i>MyWidget</i> class :<br>
<br>
<table border="1" bgcolor="#FFFFFF">
<col>
<tbody>
<tr>
<td>
<pre>MyWidget<span class="operator">::</span>MyWidget<span class="operator">() :</span> QObject<span class="operator">()
{</span><span class="comment">
//...
</span> QObject<span class="operator">::</span>connect<span class="operator">((&amp;</span> m_daoAsync<span class="operator">),</span> SIGNAL<span class="operator">(</span>queryFinished<span class="operator">(</span><span class="keyword">const</span> QSqlError<span class="operator"> &amp;,</span> qx<span class="operator">::</span>dao<span class="operator">::</span>detail<span class="operator">::</span>QxDaoAsyncParams_ptr<span class="operator">)),</span><span class="keyword">
this</span><span class="operator">,</span> SLOT<span class="operator">(</span>onQueryFinished<span class="operator">(</span><span class="keyword">const</span> QSqlError<span class="operator"> &amp;,</span> qx<span class="operator">::</span>dao<span class="operator">::</span>detail<span class="operator">::</span>QxDaoAsyncParams_ptr<span class="operator">)));</span><span class="comment">
//...
</span><span class="operator">}</span><span class="type">
void</span> MyWidget<span class="operator">::</span>onQueryFinished<span class="operator">(</span><span class="keyword">const</span> QSqlError<span class="operator"> &amp;</span> daoError<span class="operator">,</span> qx<span class="operator">::</span>dao<span class="operator">::</span>detail<span class="operator">::</span>QxDaoAsyncParams_ptr pDaoParams<span class="operator">)
{</span><span class="flow">
if</span><span class="operator"> (!</span> pDaoParams<span class="operator">) {</span><span class="flow"> return</span><span class="operator">; }</span>
qx<span class="operator">::</span>QxSqlQuery query<span class="operator"> =</span> pDaoParams<span class="operator">-&gt;</span>query<span class="operator">;</span><span class="flow">
if</span><span class="operator"> (!</span> daoError<span class="operator">.</span>isValid<span class="operator">()) { ; }</span><span class="comment">
// If the async query is associated to a simple object, just use 'pDaoParams-&gt;pInstance' method
</span> qx<span class="operator">::</span>IxPersistable_ptr ptr<span class="operator"> =</span> pDaoParams<span class="operator">-&gt;</span>pInstance<span class="operator">;</span><span class="comment">
// If the async query is associated to a list of objects, just use 'pDaoParams-&gt;pListOfInstances' method
</span> qx<span class="operator">::</span>IxPersistableCollection_ptr lst<span class="operator"> =</span> pDaoParams<span class="operator">-&gt;</span>pListOfInstances<span class="operator">;</span><span class="comment">
//...
</span><span class="operator">}</span></pre>
</td>
</tr>
</tbody>
</table>
<br>
</td>
</tr>
</tbody>
</table>
<br><br>
<a name="faq_300"><u><b>How to use <i>QxModelView</i> module to interact with Qt <i>model/view</i>
architecture (Qt widgets and/or QML views) ?</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><a href="../doxygen/html/group___qx_model_view.html" target="_blank">QxModelView</a></b> module
provides an easy way to work with <a href="http://doc.qt.io/qt-5/modelview.html" target="_blank">Qt
model/view engine</a> with all classes registered in QxOrm context :
<ul>
<li>Qt widgets : <i>QTableView</i> or <i>QListView</i> for example to display/modify a database
table content ;</li>
<li>QML : each property defined in QxOrm context is exposed to QML engine : <b><a
href="../doxygen/html/group___qx_model_view.html" target="_blank">QxModelView</a></b> module
makes easier integration between QML and databases.</li>
</ul>
<a href="../doxygen/html/classqx_1_1_ix_model.html" target="_blank">qx::IxModel</a> interface provides
a generic way for all models linked to persistents classes registered in QxOrm context. All methods of
this class prefixed by '<i>qx</i>' call functions from '<i>qx::dao</i>' namespace and then communicate
with database.<br />
<br />
The <i>qxBlogModelView</i> sample project in <i>./test/</i> directory of QxOrm package shows how to
create quickly a model and associate it to the Qt <i>model/view</i> engine (first with a Qt widget,
then with a QML view).<br />
<br />
1- Here is an example to display/modify data from '<i>author</i>' table (go to <a
href="./tutorial.html" target="_blank"><i>qxBlog</i> tutorial</a> for '<i>author</i>' class
definition) in a QTableView :<br />
<br />
<table border="1" bgcolor="#FFFFFF">
<col>
<tbody>
<tr>
<td>
<pre><span class="comment">// Create a model and fetch all data from database
</span>qx<span class="operator">::</span>IxModel<span class="operator"> *</span> pModel<span class="operator"> =</span><span class="keyword"> new</span> qx<span class="operator">::</span>QxModel<span class="operator">&lt;</span>author<span class="operator">&gt;();</span>
pModel<span class="operator">-&gt;</span>qxFetchAll<span class="operator">();</span><span class="comment">
// Associate the model to a QTableView and display it
</span>QTableView tableView<span class="operator">;</span>
tableView<span class="operator">.</span>setModel<span class="operator">(</span>pModel<span class="operator">);</span>
tableView<span class="operator">.</span>show<span class="operator">();</span></pre>
</td>
</tr>
</tbody>
</table>
<br>
After executing this code, you will have the following window :<br />
<br />
<img alt="qx_model_view_01" src="./resource/qx_model_view_01.png" border="0" /><br />
<br /><br />
2- Here is another example in QML (with Qt5, <b><a href="../doxygen/html/group___qx_model_view.html"
target="_blank">QxModelView</a></b> module works fine with Qt4 too) :<br />
<br />
<table border="1" bgcolor="#FFFFFF">
<col>
<tbody>
<tr>
<td>
<pre><span class="comment">// Create a model and fetch all data from database
</span>qx<span class="operator">::</span>IxModel<span class="operator"> *</span> pModel<span class="operator"> =</span><span class="keyword"> new</span> qx<span class="operator">::</span>QxModel<span class="operator">&lt;</span>author<span class="operator">&gt;();</span>
pModel<span class="operator">-&gt;</span>qxFetchAll<span class="operator">();</span><span class="comment">
// Associate the model to a QML view and display it
</span>QQuickView qmlView<span class="operator">;</span>
qmlView<span class="operator">.</span>rootContext<span class="operator">()-&gt;</span>setContextProperty<span class="operator">(</span><span class="string">"myModel"</span><span class="operator">,</span> pModel<span class="operator">);</span>
qmlView<span class="operator">.</span>setSource<span class="operator">(</span>QUrl<span class="operator">(</span><span class="string">"qrc:/documents/main.qml"</span><span class="operator">));</span>
qmlView<span class="operator">.</span>show<span class="operator">();</span></pre>
</td>
</tr>
</tbody>
</table>
<br>
And here is the '<i>main.qml</i>' file content :<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>
After executing this code, you will have the following window :<br />
<br />
<img alt="qx_model_view_02" src="./resource/qx_model_view_02.png" border="0" /><br />
<br />
As you can see in the '<i>main.qml</i>' file, '<i>author_id</i>' and '<i>name</i>' properties of
'<i>author</i>' model (<i>myModel</i> variable) can be automatically read and write (because they are
registered in QxOrm context).<br />
Moreover, <a href="../doxygen/html/classqx_1_1_ix_model.html" target="_blank">qx::IxModel</a>
interface provides a list of methods for QML side (<i>Q_INVOKABLE</i>) to communicate with database :
for example, the '<i>Save</i>' button will save the model in database without having to write a C++
function.<br />
<br />
<b>Note :</b> a <b>QxEntityEditor</b> plugin generates automatically the code to manage models with
relationships. Then it is possible to work with nested C++ models.<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>