3606 lines
281 KiB
HTML
3606 lines
281 KiB
HTML
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
|
||
<html>
|
||
|
||
<head>
|
||
<meta http-equiv="content-type" content="text/html; charset=iso-8859-1">
|
||
<title>QxOrm : C++ Qt ORM Object Relational Mapping database library - QxEntityEditor : C++ Qt entities graphic editor
|
||
(data model designer and source code generator)</title>
|
||
<link rel='stylesheet' type='text/css' href='./resource/qxorm_style.css'>
|
||
<script type="text/javascript" src="./resource/jquery.min.js"></script>
|
||
<script type="text/javascript" src="./resource/qxorm_script.js"></script>
|
||
</head>
|
||
|
||
<body>
|
||
<table border="0" style="width: 80%" align="center">
|
||
<col>
|
||
<col>
|
||
<col>
|
||
<col>
|
||
<col>
|
||
<tbody>
|
||
<tr>
|
||
<td><a href="./home.html"><img alt="QxOrm" src="./resource/logo_qxorm_and_qxee.png" align="left" border="0"></a>
|
||
</td>
|
||
<td align="right" style="vertical-align:bottom">
|
||
<div id="qx_search">
|
||
<gcse:search></gcse:search>
|
||
</div>
|
||
</td>
|
||
<td width="15"></td>
|
||
<td align="right" style="vertical-align:bottom">
|
||
<img alt="Windows" src="./resource/logo_windows.gif" width="35" height="35">
|
||
<img alt="Linux" src="./resource/logo_linux.gif" width="35" height="35">
|
||
<img alt="Macintosh" src="./resource/logo_mac.gif" width="35" height="35">
|
||
</td>
|
||
<td width="70"><img alt="C++" src="./resource/logo_cpp.gif" width="50" height="50" align="right"></td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
<hr style="width: 80%" align="center" size="1" color="#100D5A">
|
||
<table border="0" style="width: 80%" align="center">
|
||
<col>
|
||
<col>
|
||
<col>
|
||
<col>
|
||
<col>
|
||
<col>
|
||
<tbody>
|
||
<tr>
|
||
<td align="center"><a href="./home.html" class="btn_nav">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 >> 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 : </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<Key,
|
||
Value></i> ?</a><br>
|
||
</li>
|
||
<li><a href="#faq_81">Why does QxOrm provide a new smart-pointer <i>qx::dao::ptr<T></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 <QtCore/QString.h></i> to use the class
|
||
QString of Qt for example.<br>
|
||
In the same way, there is no need anymore to write <i>#include <boost/shared_ptr.hpp></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<Key,
|
||
Value></i> ?</b></u></a><br><br>
|
||
<table border="0" style="width: 100%" align="center">
|
||
<col>
|
||
<col>
|
||
<tbody>
|
||
<tr>
|
||
<td valign="middle" width="30"></td>
|
||
<td align="justify">
|
||
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<Key, Value></i>
|
||
?<br>
|
||
<i><a href="../doxygen/html/classqx_1_1_qx_collection.html" target="_blank">qx::QxCollection<Key,
|
||
Value></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<T></i> or
|
||
<i>QList<T></i> for example
|
||
</li>
|
||
<li>quick access to an element by a key (<i>hash-map</i>) : is equivalent to <i>QHash<Key,
|
||
Value></i> or <i>boost::unordered_map<Key, Value></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<Key, Value></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<Key,
|
||
Value></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<Key,
|
||
Value></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<Key, Value></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"><</span>drug<span class="operator">></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"><</span>QString<span class="operator">,</span> drug_ptr<span class="operator">></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">-></span>code<span class="operator"> =</span><span class="string"> "code1"</span><span class="operator">;</span> d1<span class="operator">-></span>name<span class="operator"> =</span><span class="string"> "name1"</span><span class="operator">;</span> d1<span class="operator">-></span>desc<span class="operator"> =</span><span class="string"> "desc1"</span><span class="operator">;</span>
|
||
drug_ptr d2<span class="operator">;</span> d2<span class="operator">.</span>reset<span class="operator">(</span><span class="keyword">new</span> drug<span class="operator">());</span> d2<span class="operator">-></span>code<span class="operator"> =</span><span class="string"> "code2"</span><span class="operator">;</span> d2<span class="operator">-></span>name<span class="operator"> =</span><span class="string"> "name2"</span><span class="operator">;</span> d2<span class="operator">-></span>desc<span class="operator"> =</span><span class="string"> "desc2"</span><span class="operator">;</span>
|
||
drug_ptr d3<span class="operator">;</span> d3<span class="operator">.</span>reset<span class="operator">(</span><span class="keyword">new</span> drug<span class="operator">());</span> d3<span class="operator">-></span>code<span class="operator"> =</span><span class="string"> "code3"</span><span class="operator">;</span> d3<span class="operator">-></span>name<span class="operator"> =</span><span class="string"> "name3"</span><span class="operator">;</span> d3<span class="operator">-></span>desc<span class="operator"> =</span><span class="string"> "desc3"</span><span class="operator">;</span><span class="comment">
|
||
|
||
/* insert drugs into the collection */</span>
|
||
lstDrugs<span class="operator">.</span>insert<span class="operator">(</span>d1<span class="operator">-></span>code<span class="operator">,</span> d1<span class="operator">);</span>
|
||
lstDrugs<span class="operator">.</span>insert<span class="operator">(</span>d2<span class="operator">-></span>code<span class="operator">,</span> d2<span class="operator">);</span>
|
||
lstDrugs<span class="operator">.</span>insert<span class="operator">(</span>d3<span class="operator">-></span>code<span class="operator">,</span> d3<span class="operator">);</span><span class="comment">
|
||
|
||
/* 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">() <<</span> qPrintable<span class="operator">(</span>p<span class="operator">-></span>name<span class="operator">) <<</span><span class="string"> " "</span><span class="operator"> <<</span> qPrintable<span class="operator">(</span>p<span class="operator">-></span>desc<span class="operator">); }</span><span class="comment">
|
||
|
||
/* 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"> <</span> lstDrugs<span class="operator">.</span>count<span class="operator">(); ++</span>l<span class="operator">)
|
||
{</span>
|
||
drug_ptr p<span class="operator"> =</span> lstDrugs<span class="operator">.</span>getByIndex<span class="operator">(</span>l<span class="operator">);</span>
|
||
QString code<span class="operator"> =</span> lstDrugs<span class="operator">.</span>getKeyByIndex<span class="operator">(</span>l<span class="operator">);</span>
|
||
qDebug<span class="operator">() <<</span> qPrintable<span class="operator">(</span>p<span class="operator">-></span>name<span class="operator">) <<</span><span class="string"> " "</span><span class="operator"> <<</span> qPrintable<span class="operator">(</span>p<span class="operator">-></span>desc<span class="operator">);
|
||
}</span><span class="comment">
|
||
|
||
/* iterate with 'QxCollectionIterator' java style */</span>
|
||
qx<span class="operator">::</span>QxCollectionIterator<span class="operator"><</span>QString<span class="operator">,</span> drug_ptr<span class="operator">></span> itr<span class="operator">(</span>lstDrugs<span class="operator">);</span><span class="flow">
|
||
while</span><span class="operator"> (</span>itr<span class="operator">.</span>next<span class="operator">())
|
||
{</span>
|
||
QString code<span class="operator"> =</span> itr<span class="operator">.</span>key<span class="operator">();</span>
|
||
qDebug<span class="operator">() <<</span> qPrintable<span class="operator">(</span>itr<span class="operator">.</span>value<span class="operator">()-></span>name<span class="operator">) <<</span><span class="string"> " "</span><span class="operator"> <<</span> qPrintable<span class="operator">(</span>itr<span class="operator">.</span>value<span class="operator">()-></span>desc<span class="operator">);
|
||
}</span><span class="comment">
|
||
|
||
/* 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<T></i>
|
||
?</b></u></a><br><br>
|
||
<table border="0" style="width: 100%" align="center">
|
||
<col>
|
||
<col>
|
||
<tbody>
|
||
<tr>
|
||
<td valign="middle" width="30"></td>
|
||
<td align="justify">
|
||
<b>QxOrm</b> 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<T></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<T></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<T></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<Key, Value></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"><</span>blog<span class="operator">></span> blog_isdirty<span class="operator"> =</span> qx<span class="operator">::</span>dao<span class="operator">::</span>ptr<span class="operator"><</span>blog<span class="operator">>(</span><span class="keyword">new</span> blog<span class="operator">());</span>
|
||
blog_isdirty<span class="operator">-></span>m_id<span class="operator"> =</span> blog_1<span class="operator">-></span>m_id<span class="operator">;</span>
|
||
daoError<span class="operator"> =</span> qx<span class="operator">::</span>dao<span class="operator">::</span>fetch_by_id<span class="operator">(</span>blog_isdirty<span class="operator">);</span>
|
||
qAssert<span class="operator">(!</span> daoError<span class="operator">.</span>isValid<span class="operator">() && !</span> blog_isdirty<span class="operator">.</span>isDirty<span class="operator">());</span>
|
||
|
||
blog_isdirty<span class="operator">-></span>m_text<span class="operator"> =</span><span class="string"> "blog property 'text' modified => blog is dirty !!!"</span><span class="operator">;</span>
|
||
QStringList lstDiff<span class="operator">;</span><span class="type"> bool</span> bDirty<span class="operator"> =</span> blog_isdirty<span class="operator">.</span>isDirty<span class="operator">(</span>lstDiff<span class="operator">);</span>
|
||
qAssert<span class="operator">(</span>bDirty<span class="operator"> && (</span>lstDiff<span class="operator">.</span>count<span class="operator">() ==</span><span class="int"> 1</span><span class="operator">) && (</span>lstDiff<span class="operator">.</span>at<span class="operator">(</span><span class="int">0</span><span class="operator">) ==</span><span class="string"> "blog_text"</span><span class="operator">));</span><span class="flow">
|
||
if</span><span class="operator"> (</span>bDirty<span class="operator">) {</span> qDebug<span class="operator">(</span><span class="string">"[QxOrm] test dirty 1 : blog is dirty => '%s'"</span><span class="operator">,</span> qPrintable<span class="operator">(</span>lstDiff<span class="operator">.</span>join<span class="operator">(</span><span class="string">"|"</span><span class="operator">))); }</span><span class="comment">
|
||
|
||
// 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">() && !</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"><</span> QList<span class="operator"><</span>author_ptr<span class="operator">> ></span> type_lst_author_test_is_dirty<span class="operator">;</span>
|
||
|
||
type_lst_author_test_is_dirty container_isdirty<span class="operator"> =</span> type_lst_author_test_is_dirty<span class="operator">(</span><span class="keyword">new</span> QList<span class="operator"><</span>author_ptr<span class="operator">>());</span>
|
||
daoError<span class="operator"> =</span> qx<span class="operator">::</span>dao<span class="operator">::</span>fetch_all<span class="operator">(</span>container_isdirty<span class="operator">);</span>
|
||
qAssert<span class="operator">(!</span> daoError<span class="operator">.</span>isValid<span class="operator">() && !</span> container_isdirty<span class="operator">.</span>isDirty<span class="operator">() && (</span>container_isdirty<span class="operator">-></span>count<span class="operator">() ==</span><span class="int"> 3</span><span class="operator">));</span>
|
||
|
||
author_ptr author_ptr_dirty<span class="operator"> =</span> container_isdirty<span class="operator">-></span>at<span class="operator">(</span><span class="int">1</span><span class="operator">);</span>
|
||
author_ptr_dirty<span class="operator">-></span>m_name<span class="operator"> =</span><span class="string"> "author name modified at index 1 => container is dirty !!!"</span><span class="operator">;</span>
|
||
bDirty<span class="operator"> =</span> container_isdirty<span class="operator">.</span>isDirty<span class="operator">(</span>lstDiff<span class="operator">);</span>
|
||
qAssert<span class="operator">(</span>bDirty<span class="operator"> && (</span>lstDiff<span class="operator">.</span>count<span class="operator">() ==</span><span class="int"> 1</span><span class="operator">));</span><span class="flow">
|
||
if</span><span class="operator"> (</span>bDirty<span class="operator">) {</span> qDebug<span class="operator">(</span><span class="string">"[QxOrm] test dirty 2 : container is dirty => '%s'"</span><span class="operator">,</span> qPrintable<span class="operator">(</span>lstDiff<span class="operator">.</span>join<span class="operator">(</span><span class="string">"|"</span><span class="operator">))); }</span>
|
||
|
||
author_ptr_dirty<span class="operator"> =</span> container_isdirty<span class="operator">-></span>at<span class="operator">(</span><span class="int">2</span><span class="operator">);</span>
|
||
author_ptr_dirty<span class="operator">-></span>m_birthdate<span class="operator"> =</span> QDate<span class="operator">(</span><span class="int">1998</span><span class="operator">,</span><span class="int"> 03</span><span class="operator">,</span><span class="int"> 06</span><span class="operator">);</span>
|
||
bDirty<span class="operator"> =</span> container_isdirty<span class="operator">.</span>isDirty<span class="operator">(</span>lstDiff<span class="operator">);</span>
|
||
qAssert<span class="operator">(</span>bDirty<span class="operator"> && (</span>lstDiff<span class="operator">.</span>count<span class="operator">() ==</span><span class="int"> 2</span><span class="operator">));</span><span class="flow">
|
||
if</span><span class="operator"> (</span>bDirty<span class="operator">) {</span> qDebug<span class="operator">(</span><span class="string">"[QxOrm] test dirty 3 : container is dirty => '%s'"</span><span class="operator">,</span> qPrintable<span class="operator">(</span>lstDiff<span class="operator">.</span>join<span class="operator">(</span><span class="string">"|"</span><span class="operator">))); }</span><span class="comment">
|
||
|
||
// 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">() && !</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">() <<</span><span class="string"> "date_creation"</span><span class="operator">;</span>
|
||
list_blog lst_blog_with_only_date_creation<span class="operator">;</span>
|
||
daoError<span class="operator"> =</span> qx<span class="operator">::</span>dao<span class="operator">::</span>fetch_all<span class="operator">(</span>lst_blog_with_only_date_creation<span class="operator">,</span> NULL<span class="operator">,</span> lstColumns<span class="operator">);</span>
|
||
qAssert<span class="operator">(!</span> daoError<span class="operator">.</span>isValid<span class="operator">() && (</span>lst_blog_with_only_date_creation<span class="operator">.</span>size<span class="operator">() ></span><span class="int"> 0</span><span class="operator">));</span><span class="flow">
|
||
|
||
if</span><span class="operator"> ((</span>lst_blog_with_only_date_creation<span class="operator">.</span>size<span class="operator">() ></span><span class="int"> 0</span><span class="operator">) && (</span>lst_blog_with_only_date_creation<span class="operator">[</span><span class="int">0</span><span class="operator">] !=</span> NULL<span class="operator">))
|
||
{</span> qAssert<span class="operator">(</span>lst_blog_with_only_date_creation<span class="operator">[</span><span class="int">0</span><span class="operator">]-></span>m_text<span class="operator">.</span>isEmpty<span class="operator">()); }</span>
|
||
|
||
qx<span class="operator">::</span>dump<span class="operator">(</span>lst_blog_with_only_date_creation<span class="operator">);</span></pre>
|
||
</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
<br><br>
|
||
<a name="faq_90"><u><b>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"><</span>QString<span class="operator">,</span><span class="type"> long</span><span class="operator">,</span> QString<span class="operator">></span> type_composite_key<span class="operator">;</span><span class="keyword">
|
||
static</span> QString str_composite_key<span class="operator">() {</span><span class="flow"> return</span><span class="string"> "author_id_0|author_id_1|author_id_2"</span><span class="operator">; }</span><span class="comment">
|
||
|
||
// -- typedef
|
||
</span><span class="keyword"> typedef</span> boost<span class="operator">::</span>shared_ptr<span class="operator"><</span>blog<span class="operator">></span> blog_ptr<span class="operator">;</span><span class="keyword">
|
||
typedef</span> std<span class="operator">::</span>vector<span class="operator"><</span>blog_ptr<span class="operator">></span> list_blog<span class="operator">;</span><span class="comment">
|
||
|
||
// -- enum
|
||
</span><span class="keyword"> enum</span> enum_sex<span class="operator"> {</span> male<span class="operator">,</span> female<span class="operator">,</span> unknown<span class="operator"> };</span><span class="comment">
|
||
|
||
// -- 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"><</span><span class="int">0</span><span class="operator">>(</span>m_id<span class="operator">); }</span><span class="type">
|
||
long</span> getId_1<span class="operator">()</span><span class="keyword"> const</span><span class="operator"> {</span><span class="flow"> return</span> boost<span class="operator">::</span>tuples<span class="operator">::</span>get<span class="operator"><</span><span class="int">1</span><span class="operator">>(</span>m_id<span class="operator">); }</span>
|
||
QString getId_2<span class="operator">()</span><span class="keyword"> const</span><span class="operator"> {</span><span class="flow"> return</span> boost<span class="operator">::</span>tuples<span class="operator">::</span>get<span class="operator"><</span><span class="int">2</span><span class="operator">>(</span>m_id<span class="operator">); }</span><span class="comment">
|
||
|
||
// -- 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"> &</span> s<span class="operator">) {</span> boost<span class="operator">::</span>tuples<span class="operator">::</span>get<span class="operator"><</span><span class="int">0</span><span class="operator">>(</span>m_id<span class="operator">) =</span> s<span class="operator">; }</span><span class="type">
|
||
void</span> setId_1<span class="operator">(</span><span class="type">long</span> l<span class="operator">) {</span> boost<span class="operator">::</span>tuples<span class="operator">::</span>get<span class="operator"><</span><span class="int">1</span><span class="operator">>(</span>m_id<span class="operator">) =</span> l<span class="operator">; }</span><span class="type">
|
||
void</span> setId_2<span class="operator">(</span><span class="keyword">const</span> QString<span class="operator"> &</span> s<span class="operator">) {</span> boost<span class="operator">::</span>tuples<span class="operator">::</span>get<span class="operator"><</span><span class="int">2</span><span class="operator">>(</span>m_id<span class="operator">) =</span> s<span class="operator">; }
|
||
|
||
};</span>
|
||
|
||
QX_REGISTER_PRIMARY_KEY<span class="operator">(</span>author<span class="operator">,</span> author<span class="operator">::</span>type_composite_key<span class="operator">)</span>
|
||
QX_REGISTER_HPP_QX_BLOG<span class="operator">(</span>author<span class="operator">,</span> qx<span class="operator">::</span>trait<span class="operator">::</span>no_base_class_defined<span class="operator">,</span><span class="int"> 0</span><span class="operator">)</span><span class="keyword">
|
||
|
||
typedef</span> boost<span class="operator">::</span>shared_ptr<span class="operator"><</span>author<span class="operator">></span> author_ptr<span class="operator">;</span><span class="keyword">
|
||
typedef</span> qx<span class="operator">::</span>QxCollection<span class="operator"><</span>author<span class="operator">::</span>type_composite_key<span class="operator">,</span> author_ptr<span class="operator">></span> list_author<span class="operator">;</span><span class="pre">
|
||
|
||
#endif // _QX_BLOG_AUTHOR_H_
|
||
</span></pre>
|
||
</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
<br>
|
||
<table border="1" bgcolor="#FFFFFF">
|
||
<col>
|
||
<tbody>
|
||
<tr>
|
||
<td>
|
||
<pre><span class="pre">#include "../include/precompiled.h"
|
||
#include "../include/author.h"
|
||
#include "../include/blog.h"
|
||
#include <QxOrm_Impl.h>
|
||
</span>
|
||
QX_REGISTER_CPP_QX_BLOG<span class="operator">(</span>author<span class="operator">)</span><span class="keyword">
|
||
|
||
namespace</span> qx<span class="operator"> {</span><span class="keyword">
|
||
template</span><span class="operator"> <></span><span class="type"> void</span> register_class<span class="operator">(</span>QxClass<span class="operator"><</span>author<span class="operator">> &</span> t<span class="operator">)
|
||
{</span>
|
||
t<span class="operator">.</span>id<span class="operator">(&</span> author<span class="operator">::</span>m_id<span class="operator">,</span> author<span class="operator">::</span>str_composite_key<span class="operator">());</span>
|
||
|
||
t<span class="operator">.</span>data<span class="operator">(&</span> author<span class="operator">::</span>m_name<span class="operator">,</span><span class="string"> "name"</span><span class="operator">);</span>
|
||
t<span class="operator">.</span>data<span class="operator">(&</span> author<span class="operator">::</span>m_birthdate<span class="operator">,</span><span class="string"> "birthdate"</span><span class="operator">);</span>
|
||
t<span class="operator">.</span>data<span class="operator">(&</span> author<span class="operator">::</span>m_sex<span class="operator">,</span><span class="string"> "sex"</span><span class="operator">);</span>
|
||
|
||
t<span class="operator">.</span>relationOneToMany<span class="operator">(&</span> author<span class="operator">::</span>m_blogX<span class="operator">,</span> blog<span class="operator">::</span>str_composite_key<span class="operator">(),</span> author<span class="operator">::</span>str_composite_key<span class="operator">());</span>
|
||
|
||
t<span class="operator">.</span>fct_0<span class="operator"><</span><span class="type">int</span><span class="operator">>(&</span> author<span class="operator">::</span>age<span class="operator">,</span><span class="string"> "age"</span><span class="operator">);
|
||
}}</span><span class="type">
|
||
|
||
int</span> author<span class="operator">::</span>age<span class="operator">()</span><span class="keyword"> const</span><span class="operator">
|
||
{</span><span class="flow">
|
||
if</span><span class="operator"> (!</span> m_birthdate<span class="operator">.</span>isValid<span class="operator">()) {</span><span class="flow"> return</span><span class="operator"> -</span><span class="int">1</span><span class="operator">; }</span><span class="flow">
|
||
return</span><span class="operator"> (</span>QDate<span class="operator">::</span>currentDate<span class="operator">().</span>year<span class="operator">() -</span> m_birthdate<span class="operator">.</span>year<span class="operator">());
|
||
}</span>
|
||
</pre>
|
||
</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
<br><br>
|
||
<a name="faq_105"><u><b>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<T></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 => 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"> &</span> dt<span class="operator">) {</span> m_dateCreation<span class="operator"> =</span> dt<span class="operator">; }</span><span class="type">
|
||
void</span> setDateModification<span class="operator">(</span><span class="keyword">const</span> QDateTime<span class="operator"> &</span> dt<span class="operator">) {</span> m_dateModification<span class="operator"> =</span> dt<span class="operator">; }</span><span class="type">
|
||
void</span> setUserCreation<span class="operator">(</span><span class="keyword">const</span> QString<span class="operator"> &</span> s<span class="operator">) {</span> m_userCreation<span class="operator"> =</span> s<span class="operator">; }</span><span class="type">
|
||
void</span> setUserModification<span class="operator">(</span><span class="keyword">const</span> QString<span class="operator"> &</span> s<span class="operator">) {</span> m_userModification<span class="operator"> =</span> s<span class="operator">; }</span><span class="type">
|
||
|
||
void</span> onBeforeInsert<span class="operator">(</span>qx<span class="operator">::</span>dao<span class="operator">::</span>detail<span class="operator">::</span>IxDao_Helper<span class="operator"> *</span> dao<span class="operator">);</span><span class="type">
|
||
void</span> onBeforeUpdate<span class="operator">(</span>qx<span class="operator">::</span>dao<span class="operator">::</span>detail<span class="operator">::</span>IxDao_Helper<span class="operator"> *</span> dao<span class="operator">);
|
||
|
||
};</span>
|
||
|
||
QX_REGISTER_HPP_QX_DLL2<span class="operator">(</span>BaseClassTrigger<span class="operator">,</span> qx<span class="operator">::</span>trait<span class="operator">::</span>no_base_class_defined<span class="operator">,</span><span class="int"> 0</span><span class="operator">)</span><span class="keyword">
|
||
|
||
namespace</span> qx<span class="operator"> {</span><span class="keyword">
|
||
namespace</span> dao<span class="operator"> {</span><span class="keyword">
|
||
namespace</span> detail<span class="operator"> {</span><span class="keyword">
|
||
|
||
template</span><span class="operator"> <></span><span class="keyword">
|
||
struct</span> QxDao_Trigger<span class="operator"><</span>BaseClassTrigger<span class="operator">>
|
||
{</span><span class="keyword">
|
||
|
||
static inline</span><span class="type"> void</span> onBeforeInsert<span class="operator">(</span>BaseClassTrigger<span class="operator"> *</span> t<span class="operator">,</span> qx<span class="operator">::</span>dao<span class="operator">::</span>detail<span class="operator">::</span>IxDao_Helper<span class="operator"> *</span> dao<span class="operator">)
|
||
{</span><span class="flow"> if</span><span class="operator"> (</span>t<span class="operator">) {</span> t<span class="operator">-></span>onBeforeInsert<span class="operator">(</span>dao<span class="operator">); } }</span><span class="keyword">
|
||
static inline</span><span class="type"> void</span> onBeforeUpdate<span class="operator">(</span>BaseClassTrigger<span class="operator"> *</span> t<span class="operator">,</span> qx<span class="operator">::</span>dao<span class="operator">::</span>detail<span class="operator">::</span>IxDao_Helper<span class="operator"> *</span> dao<span class="operator">)
|
||
{</span><span class="flow"> if</span><span class="operator"> (</span>t<span class="operator">) {</span> t<span class="operator">-></span>onBeforeUpdate<span class="operator">(</span>dao<span class="operator">); } }</span><span class="keyword">
|
||
static inline</span><span class="type"> void</span> onBeforeDelete<span class="operator">(</span>BaseClassTrigger<span class="operator"> *</span> t<span class="operator">,</span> qx<span class="operator">::</span>dao<span class="operator">::</span>detail<span class="operator">::</span>IxDao_Helper<span class="operator"> *</span> dao<span class="operator">)
|
||
{</span> Q_UNUSED<span class="operator">(</span>t<span class="operator">);</span> Q_UNUSED<span class="operator">(</span>dao<span class="operator">); }</span><span class="keyword">
|
||
static inline</span><span class="type"> void</span> onBeforeFetch<span class="operator">(</span>BaseClassTrigger<span class="operator"> *</span> t<span class="operator">,</span> qx<span class="operator">::</span>dao<span class="operator">::</span>detail<span class="operator">::</span>IxDao_Helper<span class="operator"> *</span> dao<span class="operator">)
|
||
{</span> Q_UNUSED<span class="operator">(</span>t<span class="operator">);</span> Q_UNUSED<span class="operator">(</span>dao<span class="operator">); }</span><span class="keyword">
|
||
static inline</span><span class="type"> void</span> onAfterInsert<span class="operator">(</span>BaseClassTrigger<span class="operator"> *</span> t<span class="operator">,</span> qx<span class="operator">::</span>dao<span class="operator">::</span>detail<span class="operator">::</span>IxDao_Helper<span class="operator"> *</span> dao<span class="operator">)
|
||
{</span> Q_UNUSED<span class="operator">(</span>t<span class="operator">);</span> Q_UNUSED<span class="operator">(</span>dao<span class="operator">); }</span><span class="keyword">
|
||
static inline</span><span class="type"> void</span> onAfterUpdate<span class="operator">(</span>BaseClassTrigger<span class="operator"> *</span> t<span class="operator">,</span> qx<span class="operator">::</span>dao<span class="operator">::</span>detail<span class="operator">::</span>IxDao_Helper<span class="operator"> *</span> dao<span class="operator">)
|
||
{</span> Q_UNUSED<span class="operator">(</span>t<span class="operator">);</span> Q_UNUSED<span class="operator">(</span>dao<span class="operator">); }</span><span class="keyword">
|
||
static inline</span><span class="type"> void</span> onAfterDelete<span class="operator">(</span>BaseClassTrigger<span class="operator"> *</span> t<span class="operator">,</span> qx<span class="operator">::</span>dao<span class="operator">::</span>detail<span class="operator">::</span>IxDao_Helper<span class="operator"> *</span> dao<span class="operator">)
|
||
{</span> Q_UNUSED<span class="operator">(</span>t<span class="operator">);</span> Q_UNUSED<span class="operator">(</span>dao<span class="operator">); }
|
||
static inline</span><span class="type"> void</span> onAfterFetch<span class="operator">(</span>BaseClassTrigger<span class="operator"> *</span> t<span class="operator">,</span> qx<span class="operator">::</span>dao<span class="operator">::</span>detail<span class="operator">::</span>IxDao_Helper<span class="operator"> *</span> dao<span class="operator">)
|
||
{</span> Q_UNUSED<span class="operator">(</span>t<span class="operator">);</span> Q_UNUSED<span class="operator">(</span>dao<span class="operator">); }
|
||
|
||
};
|
||
|
||
}</span><span class="comment"> // namespace detail
|
||
</span><span class="operator">}</span><span class="comment"> // namespace dao
|
||
</span><span class="operator">}</span><span class="comment"> // namespace qx
|
||
</span><span class="pre">
|
||
#endif // _QX_BASE_CLASS_TRIGGER_H_
|
||
</span></pre>
|
||
</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
<br>
|
||
<table border="1" bgcolor="#FFFFFF">
|
||
<col>
|
||
<tbody>
|
||
<tr>
|
||
<td>
|
||
<pre><span class="pre">#include "../include/precompiled.h"
|
||
#include "../include/BaseClassTrigger.h"
|
||
#include <QxOrm_Impl.h>
|
||
</span>
|
||
QX_REGISTER_CPP_QX_DLL2<span class="operator">(</span>BaseClassTrigger<span class="operator">)</span><span class="keyword">
|
||
|
||
namespace</span> qx<span class="operator"> {</span><span class="keyword">
|
||
template</span><span class="operator"> <></span><span class="type"> void</span> register_class<span class="operator">(</span>QxClass<span class="operator"><</span>BaseClassTrigger<span class="operator">> &</span> t<span class="operator">)
|
||
{</span>
|
||
IxDataMember<span class="operator"> *</span> pData<span class="operator"> =</span> NULL<span class="operator">;</span>
|
||
|
||
pData<span class="operator"> =</span> t<span class="operator">.</span>id<span class="operator">(&</span> BaseClassTrigger<span class="operator">::</span>m_id<span class="operator">,</span><span class="string"> "id"</span><span class="operator">);</span>
|
||
|
||
pData<span class="operator"> =</span> t<span class="operator">.</span>data<span class="operator">(&</span> BaseClassTrigger<span class="operator">::</span>m_dateCreation<span class="operator">,</span><span class="string"> "date_creation"</span><span class="operator">);</span>
|
||
pData<span class="operator"> =</span> t<span class="operator">.</span>data<span class="operator">(&</span> BaseClassTrigger<span class="operator">::</span>m_dateModification<span class="operator">,</span><span class="string"> "date_modification"</span><span class="operator">);</span>
|
||
pData<span class="operator"> =</span> t<span class="operator">.</span>data<span class="operator">(&</span> BaseClassTrigger<span class="operator">::</span>m_userCreation<span class="operator">,</span><span class="string"> "user_creation"</span><span class="operator">);</span>
|
||
pData<span class="operator"> =</span> t<span class="operator">.</span>data<span class="operator">(&</span> BaseClassTrigger<span class="operator">::</span>m_userModification<span class="operator">,</span><span class="string"> "user_modification"</span><span class="operator">);
|
||
}}</span><span class="type">
|
||
|
||
void</span> BaseClassTrigger<span class="operator">::</span>onBeforeInsert<span class="operator">(</span>qx<span class="operator">::</span>dao<span class="operator">::</span>detail<span class="operator">::</span>IxDao_Helper<span class="operator"> *</span> dao<span class="operator">)
|
||
{</span>
|
||
Q_UNUSED<span class="operator">(</span>dao<span class="operator">);</span>
|
||
m_dateCreation<span class="operator"> =</span> QDateTime<span class="operator">::</span>currentDateTime<span class="operator">();</span>
|
||
m_dateModification<span class="operator"> =</span> QDateTime<span class="operator">::</span>currentDateTime<span class="operator">();</span>
|
||
m_userCreation<span class="operator"> =</span><span class="string"> "current_user_1"</span><span class="operator">;</span>
|
||
m_userModification<span class="operator"> =</span><span class="string"> "current_user_1"</span><span class="operator">;
|
||
}</span><span class="type">
|
||
|
||
void</span> BaseClassTrigger<span class="operator">::</span>onBeforeUpdate<span class="operator">(</span>qx<span class="operator">::</span>dao<span class="operator">::</span>detail<span class="operator">::</span>IxDao_Helper<span class="operator"> *</span> dao<span class="operator">)
|
||
{</span>
|
||
Q_UNUSED<span class="operator">(</span>dao<span class="operator">);</span>
|
||
m_dateModification<span class="operator"> =</span> QDateTime<span class="operator">::</span>currentDateTime<span class="operator">();</span>
|
||
m_userModification<span class="operator"> =</span><span class="string"> "current_user_2"</span><span class="operator">;
|
||
}</span>
|
||
</pre>
|
||
</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
<br><br>
|
||
<a name="faq_140"><u><b>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<T></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"> <></span><span class="type"> void</span> register_class<span class="operator">(</span>QxClass<span class="operator"><</span>Bar<span class="operator">> &</span> t<span class="operator">)
|
||
{</span>
|
||
t<span class="operator">.</span>setSoftDelete<span class="operator">(</span>qx<span class="operator">::</span>QxSoftDelete<span class="operator">(</span><span class="string">"deleted_at"</span><span class="operator">));</span>
|
||
|
||
t<span class="operator">.</span>id<span class="operator">(&</span> Bar<span class="operator">::</span>m_id<span class="operator">,</span><span class="string"> "id"</span><span class="operator">);</span>
|
||
t<span class="operator">.</span>data<span class="operator">(&</span> Bar<span class="operator">::</span>m_desc<span class="operator">,</span><span class="string"> "desc"</span><span class="operator">);
|
||
}}</span></pre>
|
||
</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
<br>
|
||
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">-></span>setId<span class="operator">(</span><span class="int">5</span><span class="operator">);</span>
|
||
QSqlError daoError<span class="operator"> =</span> qx<span class="operator">::</span>dao<span class="operator">::</span>delete_by_id<span class="operator">(</span>pBar<span class="operator">);</span> qAssert<span class="operator">(!</span> daoError<span class="operator">.</span>isValid<span class="operator">());</span>
|
||
qx_bool bDaoExist<span class="operator"> =</span> qx<span class="operator">::</span>dao<span class="operator">::</span>exist<span class="operator">(</span>pBar<span class="operator">);</span> qAssert<span class="operator">(!</span> bDaoExist<span class="operator">);</span>
|
||
daoError<span class="operator"> =</span> qx<span class="operator">::</span>dao<span class="operator">::</span>delete_all<span class="operator"><</span>Bar<span class="operator">>();</span> qAssert<span class="operator">(!</span> daoError<span class="operator">.</span>isValid<span class="operator">());</span><span class="type">
|
||
long</span> lBarCount<span class="operator"> =</span> qx<span class="operator">::</span>dao<span class="operator">::</span>count<span class="operator"><</span>Bar<span class="operator">>();</span> qAssert<span class="operator">(</span>lBarCount<span class="operator"> ==</span><span class="int"> 0</span><span class="operator">);</span>
|
||
daoError<span class="operator"> =</span> qx<span class="operator">::</span>dao<span class="operator">::</span>destroy_all<span class="operator"><</span>Bar<span class="operator">>();</span> qAssert<span class="operator">(!</span> daoError<span class="operator">.</span>isValid<span class="operator">());</span></pre>
|
||
</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
<br>
|
||
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) => 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 => 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) => 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 => 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<T>()</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 <boost/serialization/serialization.hpp>
|
||
#include <boost/serialization/split_free.hpp>
|
||
#include <boost/serialization/nvp.hpp>
|
||
</span><span class="keyword">
|
||
namespace</span> boost<span class="operator"> {</span><span class="keyword">
|
||
namespace</span> serialization<span class="operator"> {</span><span class="keyword">
|
||
|
||
template</span><span class="operator"> <</span><span class="keyword">class</span> Archive<span class="operator">></span><span class="type">
|
||
void</span> save<span class="operator">(</span>Archive<span class="operator"> &</span> ar<span class="operator">,</span><span class="keyword"> const</span> ExtObject3D<span class="operator"> &</span> t<span class="operator">,</span><span class="type"> unsigned int</span> version<span class="operator">)
|
||
{</span>
|
||
Q_UNUSED<span class="operator">(</span>version<span class="operator">);</span><span class="type">
|
||
double</span> x<span class="operator">(</span>t<span class="operator">.</span>getX<span class="operator">()),</span> y<span class="operator">(</span>t<span class="operator">.</span>getY<span class="operator">()),</span> z<span class="operator">(</span>t<span class="operator">.</span>getZ<span class="operator">()),</span> angle<span class="operator">(</span>t<span class="operator">.</span>getAngle<span class="operator">());</span>
|
||
|
||
ar<span class="operator"> <<</span> boost<span class="operator">::</span>serialization<span class="operator">::</span>make_nvp<span class="operator">(</span><span class="string">"x"</span><span class="operator">,</span> x<span class="operator">);</span>
|
||
ar<span class="operator"> <<</span> boost<span class="operator">::</span>serialization<span class="operator">::</span>make_nvp<span class="operator">(</span><span class="string">"y"</span><span class="operator">,</span> y<span class="operator">);</span>
|
||
ar<span class="operator"> <<</span> boost<span class="operator">::</span>serialization<span class="operator">::</span>make_nvp<span class="operator">(</span><span class="string">"z"</span><span class="operator">,</span> z<span class="operator">);</span>
|
||
ar<span class="operator"> <<</span> boost<span class="operator">::</span>serialization<span class="operator">::</span>make_nvp<span class="operator">(</span><span class="string">"angle"</span><span class="operator">,</span> angle<span class="operator">);
|
||
}</span><span class="keyword">
|
||
|
||
template</span><span class="operator"> <</span><span class="keyword">class</span> Archive<span class="operator">></span><span class="type">
|
||
void</span> load<span class="operator">(</span>Archive<span class="operator"> &</span> ar<span class="operator">,</span> ExtObject3D<span class="operator"> &</span> t<span class="operator">,</span><span class="type"> unsigned int</span> version<span class="operator">)
|
||
{</span>
|
||
Q_UNUSED<span class="operator">(</span>version<span class="operator">);</span><span class="type">
|
||
double</span> x<span class="operator">(</span><span class="float">0.0</span><span class="operator">),</span> y<span class="operator">(</span><span class="float">0.0</span><span class="operator">),</span> z<span class="operator">(</span><span class="float">0.0</span><span class="operator">),</span> angle<span class="operator">(</span><span class="float">0.0</span><span class="operator">);</span>
|
||
|
||
ar<span class="operator"> >></span> boost<span class="operator">::</span>serialization<span class="operator">::</span>make_nvp<span class="operator">(</span><span class="string">"x"</span><span class="operator">,</span> x<span class="operator">);</span>
|
||
ar<span class="operator"> >></span> boost<span class="operator">::</span>serialization<span class="operator">::</span>make_nvp<span class="operator">(</span><span class="string">"y"</span><span class="operator">,</span> y<span class="operator">);</span>
|
||
ar<span class="operator"> >></span> boost<span class="operator">::</span>serialization<span class="operator">::</span>make_nvp<span class="operator">(</span><span class="string">"z"</span><span class="operator">,</span> z<span class="operator">);</span>
|
||
ar<span class="operator"> >></span> boost<span class="operator">::</span>serialization<span class="operator">::</span>make_nvp<span class="operator">(</span><span class="string">"angle"</span><span class="operator">,</span> angle<span class="operator">);</span>
|
||
|
||
t<span class="operator">.</span>setX<span class="operator">(</span>x<span class="operator">);</span>
|
||
t<span class="operator">.</span>setY<span class="operator">(</span>y<span class="operator">);</span>
|
||
t<span class="operator">.</span>setZ<span class="operator">(</span>z<span class="operator">);</span>
|
||
t<span class="operator">.</span>setAngle<span class="operator">(</span>angle<span class="operator">);
|
||
}
|
||
|
||
}</span><span class="comment"> // namespace serialization
|
||
</span><span class="operator">}</span><span class="comment"> // namespace boost
|
||
</span>
|
||
BOOST_SERIALIZATION_SPLIT_FREE<span class="operator">(</span>ExtObject3D<span class="operator">)</span><span class="pre">
|
||
|
||
#endif // _PERSIST_EXTOBJECT3D_H_</span></pre>
|
||
</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
<br>
|
||
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<mon_objet></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"> <></span><span class="keyword"> struct</span> QxConvert_ToVariant<span class="operator"><</span> ExtObject3D<span class="operator"> > {</span><span class="keyword">
|
||
static inline</span> QVariant toVariant<span class="operator">(</span><span class="keyword">const</span> ExtObject3D<span class="operator"> &</span> t<span class="operator">,</span><span class="keyword"> const</span> QString<span class="operator"> &</span> format<span class="operator">,</span><span class="type"> int</span> index<span class="operator">)
|
||
{</span><span class="comment"> /* Ici je convertis ExtObject3D en QVariant */</span><span class="operator"> } };</span><span class="keyword">
|
||
|
||
template</span><span class="operator"> <></span><span class="keyword"> struct</span> QxConvert_FromVariant<span class="operator"><</span> ExtObject3D<span class="operator"> > {</span><span class="keyword">
|
||
static inline</span> qx_bool fromVariant<span class="operator">(</span><span class="keyword">const</span> QVariant<span class="operator"> &</span> v<span class="operator">,</span> ExtObject3D<span class="operator"> &</span> t<span class="operator">,</span><span class="keyword"> const</span> QString<span class="operator"> &</span> format<span class="operator">,</span><span class="type"> int</span> index<span class="operator">)
|
||
{</span><span class="comment"> /* Ici je convertis QVariant en ExtObject3D */</span><span class="operator">;</span><span class="flow"> return</span> qx_bool<span class="operator">(</span><span class="bool">true</span><span class="operator">); } };
|
||
|
||
}</span><span class="comment"> // namespace detail
|
||
</span><span class="operator">}</span><span class="comment"> // namespace cvt
|
||
</span><span class="operator">}</span><span class="comment"> // namespace qx</span></pre>
|
||
</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
<br>
|
||
</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
<br><br>
|
||
<a name="faq_190"><u><b>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<T>()</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<T>()</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"><</span>QString<span class="operator">,</span> IxClass<span class="operator"> *> *</span> pAllClasses<span class="operator"> =</span> QxClassX<span class="operator">::</span>getAllClasses<span class="operator">();</span><span class="flow">
|
||
if</span><span class="operator"> (!</span> pAllClasses<span class="operator">) {</span> qAssert<span class="operator">(</span><span class="bool">false</span><span class="operator">);</span><span class="flow"> return</span><span class="string"> ""</span><span class="operator">; }</span>
|
||
|
||
QString sDump<span class="operator">;</span><span class="type">
|
||
long</span> lCount<span class="operator"> =</span> pAllClasses<span class="operator">-></span>count<span class="operator">();</span>
|
||
qDebug<span class="operator">(</span><span class="string">"[QxOrm] start dump all registered classes (%ld)"</span><span class="operator">,</span> lCount<span class="operator">);</span>
|
||
_foreach<span class="operator">(</span>IxClass<span class="operator"> *</span> pClass<span class="operator">, (*</span> pAllClasses<span class="operator">))
|
||
{</span><span class="flow"> if</span><span class="operator"> (</span>pClass<span class="operator">) {</span> sDump<span class="operator"> +=</span> pClass<span class="operator">-></span>dumpClass<span class="operator">(); } }</span>
|
||
qDebug<span class="operator">(</span><span class="string">"[QxOrm] %s"</span><span class="operator">,</span><span class="string"> "end dump all registered classes"</span><span class="operator">);</span><span class="flow">
|
||
|
||
return</span> sDump<span class="operator">;
|
||
}</span>
|
||
|
||
QString IxClass<span class="operator">::</span>dumpClass<span class="operator">()</span><span class="keyword"> const</span><span class="operator">
|
||
{</span>
|
||
QString sDump<span class="operator">;</span>
|
||
sDump<span class="operator"> +=</span><span class="string"> "-- class '"</span><span class="operator"> +</span> m_sKey<span class="operator"> +</span><span class="string"> "' (name '"</span><span class="operator"> +</span> m_sName<span class="operator"> +</span><span class="string"> "', "</span><span class="operator">;</span>
|
||
sDump<span class="operator"> +=</span><span class="string"> "description '"</span><span class="operator"> +</span> m_sDescription<span class="operator"> +</span><span class="string"> "', version '"</span><span class="operator"> +</span> QString<span class="operator">::</span>number<span class="operator">(</span>m_lVersion<span class="operator">) +</span><span class="string"> "', "</span><span class="operator">;</span>
|
||
sDump<span class="operator"> +=</span><span class="string"> "base class '"</span><span class="operator"> + (</span>getBaseClass<span class="operator">() ?</span> getBaseClass<span class="operator">()-></span>getKey<span class="operator">() :</span><span class="string"> ""</span><span class="operator">) +</span><span class="string"> "')\n"</span><span class="operator">;</span><span class="type">
|
||
|
||
long</span> lCount<span class="operator"> = (</span>m_pDataMemberX<span class="operator"> ?</span> m_pDataMemberX<span class="operator">-></span>count<span class="operator">() :</span><span class="int"> 0</span><span class="operator">);</span>
|
||
sDump<span class="operator"> +=</span><span class="string"> "\t* list of registered properties ("</span><span class="operator"> +</span> QString<span class="operator">::</span>number<span class="operator">(</span>lCount<span class="operator">) +</span><span class="string"> ")\n"</span><span class="operator">;</span><span class="flow">
|
||
if</span><span class="operator"> (</span>m_pDataMemberX<span class="operator">)
|
||
{</span>
|
||
IxDataMember<span class="operator"> *</span> pId<span class="operator"> =</span><span class="keyword"> this</span><span class="operator">-></span>getId<span class="operator">();</span><span class="flow">
|
||
for</span><span class="operator"> (</span><span class="type">long</span> l<span class="operator"> =</span><span class="int"> 0</span><span class="operator">;</span> l<span class="operator"> <</span> lCount<span class="operator">;</span> l<span class="operator">++)
|
||
{</span>
|
||
IxDataMember<span class="operator"> *</span> p<span class="operator"> =</span> m_pDataMemberX<span class="operator">-></span>get<span class="operator">(</span>l<span class="operator">);</span><span class="flow"> if</span><span class="operator"> (!</span> p<span class="operator">) {</span><span class="flow"> continue</span><span class="operator">; }</span>
|
||
IxSqlRelation<span class="operator"> *</span> pRelation<span class="operator"> =</span> p<span class="operator">-></span>getSqlRelation<span class="operator">();</span>
|
||
QString sInfos<span class="operator"> =</span> p<span class="operator">-></span>getKey<span class="operator">() + ((</span>p<span class="operator"> ==</span> pId<span class="operator">) ?</span> QString<span class="operator">(</span><span class="string">" (id)"</span><span class="operator">) :</span> QString<span class="operator">());</span>
|
||
sInfos<span class="operator"> += (</span>pRelation<span class="operator"> ? (</span>QString<span class="operator">(</span><span class="string">" ("</span><span class="operator">) +</span> pRelation<span class="operator">-></span>getDescription<span class="operator">() +</span> QString<span class="operator">(</span><span class="string">")"</span><span class="operator">)) :</span> QString<span class="operator">());</span>
|
||
sDump<span class="operator"> +=</span><span class="string"> "\t\t"</span><span class="operator"> +</span> sInfos<span class="operator"> +</span><span class="string"> "\n"</span><span class="operator">;
|
||
}
|
||
}</span>
|
||
|
||
lCount<span class="operator"> = (</span>m_pFctMemberX<span class="operator"> ?</span> m_pFctMemberX<span class="operator">-></span>count<span class="operator">() :</span><span class="int"> 0</span><span class="operator">);</span>
|
||
sDump<span class="operator"> +=</span><span class="string"> "\t* list of registered functions ("</span><span class="operator"> +</span> QString<span class="operator">::</span>number<span class="operator">(</span>lCount<span class="operator">) +</span><span class="string"> ")\n"</span><span class="operator">;</span><span class="flow">
|
||
if</span><span class="operator"> (</span>m_pFctMemberX<span class="operator">)
|
||
{</span>
|
||
_foreach_if<span class="operator">(</span>IxFunction_ptr p<span class="operator">, (*</span> m_pFctMemberX<span class="operator">), (</span>p<span class="operator">))
|
||
{</span> QString sKey<span class="operator"> =</span> p<span class="operator">-></span>getKey<span class="operator">();</span> sDump<span class="operator"> +=</span><span class="string"> "\t\t"</span><span class="operator"> +</span> sKey<span class="operator"> +</span><span class="string"> "\n"</span><span class="operator">; }
|
||
}</span>
|
||
|
||
qDebug<span class="operator">(</span><span class="string">"%s"</span><span class="operator">,</span> qPrintable<span class="operator">(</span>sDump<span class="operator">));</span><span class="flow">
|
||
return</span> sDump<span class="operator">;
|
||
}</span></pre>
|
||
</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
<br>
|
||
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<T>()</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<T>()</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"> &</span> s<span class="operator">) {</span> m_desc<span class="operator"> =</span> s<span class="operator">; }</span><span class="type">
|
||
void</span> setBirthDate<span class="operator">(</span><span class="keyword">const</span> QDateTime<span class="operator"> &</span> dt<span class="operator">) {</span> m_birthDate<span class="operator"> =</span> dt<span class="operator">; }</span><span class="type">
|
||
void</span> setPhoto<span class="operator">(</span><span class="keyword">const</span> QVariant<span class="operator"> &</span> v<span class="operator">) {</span> m_photo<span class="operator"> =</span> v<span class="operator">; }
|
||
|
||
};</span>
|
||
|
||
QX_REGISTER_HPP_QX_DLL1<span class="operator">(</span>TestQtProperty<span class="operator">,</span> QObject<span class="operator">,</span><span class="int"> 0</span><span class="operator">)</span><span class="pre">
|
||
|
||
#endif // _QX_TEST_QT_META_PROPERTY_H_</span></pre>
|
||
</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
<br>
|
||
<table border="1" bgcolor="#FFFFFF">
|
||
<col>
|
||
<tbody>
|
||
<tr>
|
||
<td title="TestQtProperty.cpp">
|
||
<pre><span class="pre">#include "../include/precompiled.h"
|
||
|
||
#include "../include/TestQtProperty.h"
|
||
|
||
#include <QxOrm_Impl.h>
|
||
</span>
|
||
QX_REGISTER_CPP_QX_DLL1<span class="operator">(</span>TestQtProperty<span class="operator">)</span>
|
||
QX_REGISTER_ALL_QT_PROPERTIES<span class="operator">(</span>TestQtProperty<span class="operator">,</span><span class="string"> "id"</span><span class="operator">)</span></pre>
|
||
</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
<br>
|
||
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"> <></span><span class="type"> void</span> register_class<span class="operator">(</span>QxClass<span class="operator"><</span>TestQtProperty<span class="operator">> &</span> t<span class="operator">)
|
||
{</span> qx<span class="operator">::</span>register_all_qt_properties<span class="operator"><</span>TestQtProperty<span class="operator">>(</span>t<span class="operator">,</span><span class="string"> "id"</span><span class="operator">); }
|
||
}</span><span class="comment"> // namespace qx</span></pre>
|
||
</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
<br>
|
||
<b>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<T>()</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"><</span>author<span class="operator">></span> list_of_female<span class="operator">;</span>
|
||
QSqlError daoError<span class="operator"> =</span> qx<span class="operator">::</span>dao<span class="operator">::</span>fetch_by_query<span class="operator">(</span>query<span class="operator">,</span> list_of_female<span class="operator">);</span><span class="flow">
|
||
for</span><span class="operator"> (</span><span class="type">long</span> l<span class="operator"> =</span><span class="int"> 0</span><span class="operator">;</span> l<span class="operator"> <</span> list_of_female<span class="operator">.</span>count<span class="operator">();</span> l<span class="operator">++)
|
||
{</span><span class="comment"> /* 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"><</span>author<span class="operator">></span> list_of_female<span class="operator">;</span>
|
||
QSqlError daoError<span class="operator"> =</span> qx<span class="operator">::</span>dao<span class="operator">::</span>fetch_by_query<span class="operator">(</span>query<span class="operator">,</span> list_of_female<span class="operator">);</span><span class="flow">
|
||
for</span><span class="operator"> (</span><span class="type">long</span> l<span class="operator"> =</span><span class="int"> 0</span><span class="operator">;</span> l<span class="operator"> <</span> list_of_female<span class="operator">.</span>count<span class="operator">();</span> l<span class="operator">++)
|
||
{</span><span class="comment"> /* 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"> > :</span>age_3_0
|
||
OR last_name<span class="operator"> <> :</span>last_name_5_0
|
||
OR first_name LIKE<span class="operator"> :</span>first_name_7_0
|
||
AND<span class="operator"> (</span> id<span class="operator"> <= :</span>id_10_0 AND birth_date BETWEEN<span class="operator"> :</span>birth_date_12_0_1 AND<span class="operator"> :</span>birth_date_12_0_2<span class="operator"> )</span>
|
||
OR id IN<span class="operator"> (:</span>id_15_0_0<span class="operator">, :</span>id_15_0_1<span class="operator">, :</span>id_15_0_2<span class="operator">, :</span>id_15_0_3<span class="operator">, :</span>id_15_0_4<span class="operator">)</span>
|
||
AND is_deleted IS NOT NULL
|
||
ORDER BY last_name ASC<span class="operator">,</span> first_name ASC<span class="operator">,</span> sex ASC
|
||
LIMIT<span class="operator"> :</span>limit_rows_count_19_0 OFFSET<span class="operator"> :</span>offset_start_row_19_0</pre>
|
||
</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
<br>
|
||
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"><</span>T<span class="operator">>()</span>
|
||
qx<span class="operator">::</span>dao<span class="operator">::</span>fetch_by_query<span class="operator"><</span>T<span class="operator">>()</span>
|
||
qx<span class="operator">::</span>dao<span class="operator">::</span>update_by_query<span class="operator"><</span>T<span class="operator">>()</span>
|
||
qx<span class="operator">::</span>dao<span class="operator">::</span>delete_by_query<span class="operator"><</span>T<span class="operator">>()</span>
|
||
qx<span class="operator">::</span>dao<span class="operator">::</span>destroy_by_query<span class="operator"><</span>T<span class="operator">>()</span>
|
||
qx<span class="operator">::</span>dao<span class="operator">::</span>fetch_by_query_with_relation<span class="operator"><</span>T<span class="operator">>()</span>
|
||
qx<span class="operator">::</span>dao<span class="operator">::</span>fetch_by_query_with_all_relation<span class="operator"><</span>T<span class="operator">>()</span>
|
||
qx<span class="operator">::</span>dao<span class="operator">::</span>update_by_query_with_relation<span class="operator"><</span>T<span class="operator">>()</span>
|
||
qx<span class="operator">::</span>dao<span class="operator">::</span>update_by_query_with_all_relation<span class="operator"><</span>T<span class="operator">>()</span>
|
||
qx<span class="operator">::</span>dao<span class="operator">::</span>update_optimized_by_query<span class="operator"><</span>T<span class="operator">>()</span><span class="comment">
|
||
|
||
// with qx::QxSession class
|
||
</span>qx<span class="operator">::</span>QxSession<span class="operator">::</span>count<span class="operator"><</span>T<span class="operator">>()</span>
|
||
qx<span class="operator">::</span>QxSession<span class="operator">::</span>fetchByQuery<span class="operator"><</span>T<span class="operator">>()</span>
|
||
qx<span class="operator">::</span>QxSession<span class="operator">::</span>update<span class="operator"><</span>T<span class="operator">>()</span>
|
||
qx<span class="operator">::</span>QxSession<span class="operator">::</span>deleteByQuery<span class="operator"><</span>T<span class="operator">>()</span>
|
||
qx<span class="operator">::</span>QxSession<span class="operator">::</span>destroyByQuery<span class="operator"><</span>T<span class="operator">>()</span><span class="comment">
|
||
|
||
// with qx::QxRepository<T> class
|
||
</span>qx<span class="operator">::</span>QxRepository<span class="operator"><</span>T<span class="operator">>::</span>count<span class="operator">()</span>
|
||
qx<span class="operator">::</span>QxRepository<span class="operator"><</span>T<span class="operator">>::</span>fetchByQuery<span class="operator">()</span>
|
||
qx<span class="operator">::</span>QxRepository<span class="operator"><</span>T<span class="operator">>::</span>update<span class="operator">()</span>
|
||
qx<span class="operator">::</span>QxRepository<span class="operator"><</span>T<span class="operator">>::</span>deleteByQuery<span class="operator">()</span>
|
||
qx<span class="operator">::</span>QxRepository<span class="operator"><</span>T<span class="operator">>::</span>destroyByQuery<span class="operator">()</span></pre>
|
||
</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
<br>
|
||
<b>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<T>()</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<T></i></a> of <i>boost</i> library or <a
|
||
href="http://doc-snapshots.qt.io/4.8/qsharedpointer.html"
|
||
target="_blank"><i>QSharedPointer<T></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"><</span> QList<span class="operator"><</span>author<span class="operator">> ></span> list_author<span class="operator">;</span>
|
||
QSqlError daoError<span class="operator"> =</span> qx<span class="operator">::</span>dao<span class="operator">::</span>fetch_all<span class="operator">(</span>list_author<span class="operator">);</span><span class="comment">
|
||
|
||
// 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"><</span> std<span class="operator">::</span>vector<span class="operator"><</span>blog<span class="operator">> ></span> list_blog<span class="operator">;</span>
|
||
daoError<span class="operator"> =</span> qx<span class="operator">::</span>dao<span class="operator">::</span>fetch_all<span class="operator">(</span>list_blog<span class="operator">);</span><span class="comment">
|
||
|
||
// 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">-></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"><</span> QSharedPointer<span class="operator"><</span> std<span class="operator">::</span>vector<span class="operator"><</span>blog<span class="operator">> > >(</span><span class="string">"list_blog"</span><span class="operator">);</span><span class="comment">
|
||
|
||
// 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<T></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 <QxOrm_Impl.h>
|
||
</span>
|
||
QX_REGISTER_CPP_MY_APP<span class="operator">(</span>DatabaseVersion<span class="operator">)</span><span class="keyword">
|
||
|
||
namespace</span> qx<span class="operator"> {</span><span class="keyword">
|
||
template</span><span class="operator"> <></span><span class="type"> void</span> register_class<span class="operator">(</span>QxClass<span class="operator"><</span>DatabaseVersion<span class="operator">> &</span> t<span class="operator">)
|
||
{</span>
|
||
t<span class="operator">.</span>id<span class="operator">(&</span> DatabaseVersion<span class="operator">::</span>name<span class="operator">,</span><span class="string"> "name"</span><span class="operator">);</span>
|
||
t<span class="operator">.</span>data<span class="operator">(&</span> DatabaseVersion<span class="operator">::</span>version<span class="operator">,</span><span class="string"> "version"</span><span class="operator">);
|
||
}}</span></pre>
|
||
</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
<br>
|
||
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"> <</span> qApp<span class="operator">-></span>property<span class="operator">(</span><span class="string">"DomainVersion"</span><span class="operator">).</span>toInt<span class="operator">());
|
||
}</span></pre>
|
||
</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
<br>
|
||
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">-></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">()-></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"> >=</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"><</span>QString<span class="operator">,</span> qx<span class="operator">::</span>IxClass<span class="operator"> *> *</span> pAllClasses<span class="operator"> =</span> qx<span class="operator">::</span>QxClassX<span class="operator">::</span>getAllClasses<span class="operator">();</span><span class="flow">
|
||
if</span><span class="operator"> (!</span> pAllClasses<span class="operator">) {</span> qAssert<span class="operator">(</span><span class="bool">false</span><span class="operator">);</span><span class="flow"> return</span><span class="operator">; }</span><span class="comment">
|
||
|
||
// 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"> <</span> pAllClasses<span class="operator">-></span>count<span class="operator">();</span> k<span class="operator">++)
|
||
{</span>
|
||
qx<span class="operator">::</span>IxClass<span class="operator"> *</span> pClass<span class="operator"> =</span> pAllClasses<span class="operator">-></span>getByIndex<span class="operator">(</span>k<span class="operator">);</span><span class="flow">
|
||
if</span><span class="operator"> (!</span> pClass<span class="operator">) {</span><span class="flow"> continue</span><span class="operator">; }</span><span class="comment">
|
||
|
||
// Filter non persitents classes
|
||
</span><span class="flow"> if</span><span class="operator"> (</span>pClass<span class="operator">-></span>isKindOf<span class="operator">(</span><span class="string">"qx::service::IxParameter"</span><span class="operator">) ||</span> pClass<span class="operator">-></span>isKindOf<span class="operator">(</span><span class="string">"qx::service::IxService"</span><span class="operator">)) {</span><span class="flow"> continue</span><span class="operator">; }</span><span class="comment">
|
||
|
||
// Filter already updated classes
|
||
</span><span class="flow"> if</span><span class="operator"> (</span>pClass<span class="operator">-></span>getVersion<span class="operator">() <=</span> dbVersion<span class="operator">.</span>version<span class="operator">) {</span><span class="flow"> continue</span><span class="operator">; }</span><span class="comment">
|
||
|
||
// 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">-></span>getName<span class="operator">()))
|
||
{</span>
|
||
query<span class="operator">.</span>exec<span class="operator">(</span><span class="string">"CREATE TABLE "</span><span class="operator"> +</span> pClass<span class="operator">-></span>getName<span class="operator">() +</span><span class="string"> " ( ) WITH (OIDS = FALSE);"
|
||
"ALTER TABLE "</span><span class="operator"> +</span> pClass<span class="operator">-></span>getName<span class="operator">() +</span><span class="string"> " OWNER TO \"MyAdminLogin\";"</span><span class="operator">);</span>
|
||
session<span class="operator"> +=</span> query<span class="operator">.</span>lastError<span class="operator">();
|
||
}</span><span class="comment">
|
||
|
||
// 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">-></span>getDataMemberX<span class="operator">();</span><span class="flow">
|
||
for</span><span class="operator"> (</span><span class="type">long</span> l<span class="operator"> =</span><span class="int"> 0</span><span class="operator">; (</span>pDataMemberX<span class="operator"> && (</span>l<span class="operator"> <</span> pDataMemberX<span class="operator">-></span>count_WithDaoStrategy<span class="operator">()));</span> l<span class="operator">++)
|
||
{</span>
|
||
qx<span class="operator">::</span>IxDataMember<span class="operator"> *</span> p<span class="operator"> =</span> pDataMemberX<span class="operator">-></span>get_WithDaoStrategy<span class="operator">(</span>l<span class="operator">);</span><span class="flow">
|
||
if</span><span class="operator"> (!</span> p<span class="operator"> || (</span>p<span class="operator">-></span>getVersion<span class="operator">() <=</span> dbVersion<span class="operator">.</span>version<span class="operator">)) {</span><span class="flow"> continue</span><span class="operator">; }</span>
|
||
|
||
query<span class="operator">.</span>exec<span class="operator">(</span><span class="string">"ALTER TABLE "</span><span class="operator"> +</span> pClass<span class="operator">-></span>getName<span class="operator">() +</span><span class="string"> " ADD COLUMN "</span><span class="operator"> +</span> p<span class="operator">-></span>getName<span class="operator">() +</span><span class="string"> " "</span><span class="operator"> +</span> p<span class="operator">-></span>getSqlType<span class="operator">() +</span><span class="string"> ";"</span><span class="operator">);</span>
|
||
session<span class="operator"> +=</span> query<span class="operator">.</span>lastError<span class="operator">();</span><span class="flow">
|
||
|
||
if</span><span class="operator"> (</span>p<span class="operator">-></span>getIsPrimaryKey<span class="operator">())</span><span class="comment"> // PRIMARY KEY
|
||
</span><span class="operator"> {</span>
|
||
query<span class="operator">.</span>exec<span class="operator">(</span><span class="string">"ALTER TABLE "</span><span class="operator"> +</span> pClass<span class="operator">-></span>getName<span class="operator">() +</span><span class="string"> " ADD PRIMARY KEY ("</span><span class="operator"> +</span> p<span class="operator">-></span>getName<span class="operator">() +</span><span class="string"> ");"</span><span class="operator">);</span>
|
||
session<span class="operator"> +=</span> query<span class="operator">.</span>lastError<span class="operator">();
|
||
}</span><span class="flow">
|
||
|
||
if</span><span class="operator"> (</span>p<span class="operator">-></span>getAllPropertyBagKeys<span class="operator">().</span>contains<span class="operator">(</span><span class="string">"INDEX"</span><span class="operator">))</span><span class="comment"> // INDEX
|
||
</span><span class="operator"> {</span>
|
||
query<span class="operator">.</span>exec<span class="operator">(</span><span class="string">"CREATE INDEX "</span><span class="operator"> +</span> pClass<span class="operator">-></span>getName<span class="operator">() +</span><span class="string"> "_"</span><span class="operator"> +</span> p<span class="operator">-></span>getName<span class="operator">() +</span><span class="string"> "_idx"</span><span class="operator"> +</span><span class="string">
|
||
" ON "</span><span class="operator"> +</span> pClass<span class="operator">-></span>getName<span class="operator">() +</span><span class="string"> " USING "</span><span class="operator"> +</span> p<span class="operator">-></span>getPropertyBag<span class="operator">(</span><span class="string">"INDEX"</span><span class="operator">).</span>toString<span class="operator">() +</span><span class="string"> " ("</span><span class="operator"> +</span> p<span class="operator">-></span>getName<span class="operator">() +</span><span class="string"> ");"</span><span class="operator">);</span>
|
||
session<span class="operator"> +=</span> query<span class="operator">.</span>lastError<span class="operator">();
|
||
}</span><span class="flow">
|
||
|
||
if</span><span class="operator"> (</span>p<span class="operator">-></span>getNotNull<span class="operator">())</span><span class="comment"> // NOT NULL
|
||
</span><span class="operator"> {</span>
|
||
query<span class="operator">.</span>exec<span class="operator">(</span><span class="string">"ALTER TABLE "</span><span class="operator"> +</span> pClass<span class="operator">-></span>getName<span class="operator">() +</span><span class="string"> " ALTER COLUMN "</span><span class="operator"> +</span> p<span class="operator">-></span>getName<span class="operator">() +</span><span class="string"> " SET NOT NULL;"</span><span class="operator">);</span>
|
||
session<span class="operator"> +=</span> query<span class="operator">.</span>lastError<span class="operator">();
|
||
}</span><span class="flow">
|
||
|
||
if</span><span class="operator"> (</span>p<span class="operator">-></span>getAutoIncrement<span class="operator">())</span><span class="comment"> // AUTO INCREMENT
|
||
</span><span class="operator"> {</span>
|
||
query<span class="operator">.</span>exec<span class="operator">(</span><span class="string">"CREATE SEQUENCE "</span><span class="operator"> +</span> pClass<span class="operator">-></span>getName<span class="operator">() +</span><span class="string"> "_"</span><span class="operator"> +</span> p<span class="operator">-></span>getName<span class="operator">() +</span><span class="string"> "_seq"</span><span class="operator"> +</span><span class="string"> "; "
|
||
"ALTER TABLE "</span><span class="operator"> +</span> pClass<span class="operator">-></span>getName<span class="operator">() +</span><span class="string"> "_"</span><span class="operator"> +</span> p<span class="operator">-></span>getName<span class="operator">() +</span><span class="string"> "_seq"</span><span class="operator"> +</span><span class="string"> " OWNER TO \"MyAdminLogin\"; "
|
||
"ALTER TABLE "</span><span class="operator"> +</span> pClass<span class="operator">-></span>getName<span class="operator">() +</span><span class="string"> " ALTER COLUMN "</span><span class="operator"> +</span> p<span class="operator">-></span>getName<span class="operator">() +</span><span class="string"> " "</span><span class="operator"> +</span><span class="string">
|
||
"SET DEFAULT nextval('"</span><span class="operator"> +</span> pClass<span class="operator">-></span>getName<span class="operator">() +</span><span class="string"> "_"</span><span class="operator"> +</span> p<span class="operator">-></span>getName<span class="operator">() +</span><span class="string"> "_seq"</span><span class="operator"> +</span><span class="string"> "'::regclass);"</span><span class="operator">);</span>
|
||
session<span class="operator"> +=</span> query<span class="operator">.</span>lastError<span class="operator">();
|
||
}</span><span class="flow">
|
||
|
||
if</span><span class="operator"> (</span>p<span class="operator">-></span>getDescription<span class="operator">() !=</span><span class="string"> ""</span><span class="operator">)</span><span class="comment"> // DESCRIPTION
|
||
</span><span class="operator"> {</span> query<span class="operator">.</span>exec<span class="operator">(</span><span class="string">"COMMENT ON COLUMN "</span><span class="operator"> +</span> pClass<span class="operator">-></span>getName<span class="operator">() +</span><span class="string"> "."</span><span class="operator"> +</span> p<span class="operator">-></span>getName<span class="operator">() +</span><span class="string"> " IS $$"</span><span class="operator"> +</span> p<span class="operator">-></span>getDescription<span class="operator">() +</span><span class="string"> "$$ ;"</span><span class="operator">);</span>
|
||
session<span class="operator"> +=</span> query<span class="operator">.</span>lastError<span class="operator">();
|
||
}
|
||
}
|
||
}</span><span class="comment">
|
||
|
||
// 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 => 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"> &</span> err<span class="operator">)
|
||
{</span>
|
||
QSqlError sqlError<span class="operator"> =</span> err<span class="operator">.</span>get<span class="operator">();</span>
|
||
qDebug<span class="operator">() <<</span> sqlError<span class="operator">.</span>databaseText<span class="operator">();</span>
|
||
qDebug<span class="operator">() <<</span> sqlError<span class="operator">.</span>driverText<span class="operator">();</span>
|
||
qDebug<span class="operator">() <<</span> sqlError<span class="operator">.</span>number<span class="operator">();</span>
|
||
qDebug<span class="operator">() <<</span> sqlError<span class="operator">.</span>type<span class="operator">();
|
||
}
|
||
}</span></pre>
|
||
</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
<br>
|
||
<b>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"> <-></span><span class="string"> "SMALLINT"
|
||
"qx_bool"</span><span class="operator"> <-></span><span class="string"> "SMALLINT"
|
||
"short"</span><span class="operator"> <-></span><span class="string"> "SMALLINT"
|
||
"int"</span><span class="operator"> <-></span><span class="string"> "INTEGER"
|
||
"long"</span><span class="operator"> <-></span><span class="string"> "INTEGER"
|
||
"long long"</span><span class="operator"> <-></span><span class="string"> "INTEGER"
|
||
"float"</span><span class="operator"> <-></span><span class="string"> "FLOAT"
|
||
"double"</span><span class="operator"> <-></span><span class="string"> "FLOAT"
|
||
"long double"</span><span class="operator"> <-></span><span class="string"> "FLOAT"
|
||
"unsigned short"</span><span class="operator"> <-></span><span class="string"> "SMALLINT"
|
||
"unsigned int"</span><span class="operator"> <-></span><span class="string"> "INTEGER"
|
||
"unsigned long"</span><span class="operator"> <-></span><span class="string"> "INTEGER"
|
||
"unsigned long long"</span><span class="operator"> <-></span><span class="string"> "INTEGER"
|
||
"std::string"</span><span class="operator"> <-></span><span class="string"> "TEXT"
|
||
"std::wstring"</span><span class="operator"> <-></span><span class="string"> "TEXT"
|
||
"QString"</span><span class="operator"> <-></span><span class="string"> "TEXT"
|
||
"QVariant"</span><span class="operator"> <-></span><span class="string"> "TEXT"
|
||
"QUuid"</span><span class="operator"> <-></span><span class="string"> "TEXT"
|
||
"QDate"</span><span class="operator"> <-></span><span class="string"> "DATE"
|
||
"QTime"</span><span class="operator"> <-></span><span class="string"> "TIME"
|
||
"QDateTime"</span><span class="operator"> <-></span><span class="string"> "TIMESTAMP"
|
||
"QByteArray"</span><span class="operator"> <-></span><span class="string"> "BLOB"
|
||
"qx::QxDateNeutral"</span><span class="operator"> <-></span><span class="string"> "TEXT"
|
||
"qx::QxTimeNeutral"</span><span class="operator"> <-></span><span class="string"> "TEXT"
|
||
"qx::QxDateTimeNeutral"</span><span class="operator"> <-></span><span class="string"> "TEXT"</span></pre>
|
||
</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
<br>
|
||
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"><</span>QString<span class="operator">,</span> QString<span class="operator">> *</span> lstSqlType<span class="operator"> =</span> qx<span class="operator">::</span>QxClassX<span class="operator">::</span>getAllSqlTypeByClassName<span class="operator">();</span>
|
||
lstSqlType<span class="operator">-></span>insert<span class="operator">(</span><span class="string">"QString"</span><span class="operator">,</span><span class="string"> "VARCHAR(255)"</span><span class="operator">);</span>
|
||
lstSqlType<span class="operator">-></span>insert<span class="operator">(</span><span class="string">"std::string"</span><span class="operator">,</span><span class="string"> "VARCHAR(255)"</span><span class="operator">);</span><span class="comment">
|
||
// etc.</span></pre>
|
||
</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
<br>
|
||
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"> <></span><span class="type"> void</span> register_class<span class="operator">(</span>QxClass<span class="operator"><</span>MyClass<span class="operator">> &</span> t<span class="operator">)
|
||
{</span><span class="comment">
|
||
//...
|
||
</span> IxDataMember<span class="operator"> *</span> p<span class="operator"> =</span> t<span class="operator">.</span>data<span class="operator">(&</span> MyClass<span class="operator">::</span>m_MyProperty<span class="operator">,</span><span class="string"> "my_property"</span><span class="operator">);</span>
|
||
p<span class="operator">-></span>setSqlType<span class="operator">(</span><span class="string">"VARCHAR(255)"</span><span class="operator">);</span><span class="comment">
|
||
//...
|
||
</span><span class="operator">}}</span></pre>
|
||
</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
<br>
|
||
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"> &</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 <QxOrm_Impl.h>
|
||
</span>
|
||
QX_REGISTER_CPP_MY_EXE<span class="operator">(</span>person<span class="operator">)</span><span class="keyword">
|
||
|
||
namespace</span> qx<span class="operator"> {</span><span class="keyword">
|
||
template</span><span class="operator"> <></span><span class="type"> void</span> register_class<span class="operator">(</span>QxClass<span class="operator"><</span>person<span class="operator">> &</span> t<span class="operator">)
|
||
{</span>
|
||
t<span class="operator">.</span>id<span class="operator">(&</span> person<span class="operator">::</span>_id<span class="operator">,</span><span class="string"> "id"</span><span class="operator">);</span>
|
||
|
||
t<span class="operator">.</span>data<span class="operator">(&</span> person<span class="operator">::</span>_firstName<span class="operator">,</span><span class="string"> "firstName"</span><span class="operator">);</span>
|
||
t<span class="operator">.</span>data<span class="operator">(&</span> person<span class="operator">::</span>_lastName<span class="operator">,</span><span class="string"> "lastName"</span><span class="operator">);</span>
|
||
t<span class="operator">.</span>data<span class="operator">(&</span> person<span class="operator">::</span>_birthDate<span class="operator">,</span><span class="string"> "birthDate"</span><span class="operator">);</span>
|
||
t<span class="operator">.</span>data<span class="operator">(&</span> person<span class="operator">::</span>_sex<span class="operator">,</span><span class="string"> "sex"</span><span class="operator">);</span>
|
||
|
||
QxValidatorX<span class="operator"><</span>person<span class="operator">> *</span> pAllValidator<span class="operator"> =</span> t<span class="operator">.</span>getAllValidator<span class="operator">();</span>
|
||
pAllValidator<span class="operator">-></span>add_NotEmpty<span class="operator">(</span><span class="string">"firstName"</span><span class="operator">);</span>
|
||
pAllValidator<span class="operator">-></span>add_NotEmpty<span class="operator">(</span><span class="string">"lastName"</span><span class="operator">,</span><span class="string"> "a person must have a lastname"</span><span class="operator">);</span>
|
||
pAllValidator<span class="operator">-></span>add_CustomValidator<span class="operator">(&</span> person<span class="operator">::</span>isValid<span class="operator">);</span>
|
||
pAllValidator<span class="operator">-></span>add_CustomValidator_QVariant<span class="operator">(&</span> validateFirstName<span class="operator">,</span><span class="string"> "firstName"</span><span class="operator">);</span>
|
||
pAllValidator<span class="operator">-></span>add_CustomValidator_DataType<span class="operator"><</span>QDateTime<span class="operator">>(&</span> validateDateTime<span class="operator">,</span><span class="string"> "birthDate"</span><span class="operator">);
|
||
}}</span><span class="type">
|
||
|
||
void</span> person<span class="operator">::</span>isValid<span class="operator">(</span>qx<span class="operator">::</span>QxInvalidValueX<span class="operator"> &</span> invalidValues<span class="operator">)
|
||
{</span><span class="comment">
|
||
// 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">) && (</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"> &</span> value<span class="operator">,</span><span class="keyword"> const</span> qx<span class="operator">::</span>IxValidator<span class="operator"> *</span> validator<span class="operator">,</span> qx<span class="operator">::</span>QxInvalidValueX<span class="operator"> &</span> invalidValues<span class="operator">)
|
||
{</span><span class="comment">
|
||
// 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"> &</span> value<span class="operator">,</span><span class="keyword"> const</span> qx<span class="operator">::</span>IxValidator<span class="operator"> *</span> validator<span class="operator">,</span> qx<span class="operator">::</span>QxInvalidValueX<span class="operator"> &</span> invalidValues<span class="operator">)
|
||
{</span><span class="comment">
|
||
// 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"> &</span> query<span class="operator"> =</span> qx<span class="operator">::</span>QxSqlQuery<span class="operator">(),</span> QSqlDatabase<span class="operator"> *</span> pDatabase<span class="operator"> =</span> NULL<span class="operator">);</span><span class="keyword">
|
||
virtual</span> QSqlError qxFetchById<span class="operator">(</span><span class="keyword">const</span> QVariant<span class="operator"> &</span> id<span class="operator"> =</span> QVariant<span class="operator">(),</span><span class="keyword"> const</span> QStringList<span class="operator"> &</span> columns<span class="operator"> =</span> QStringList<span class="operator">(),</span><span class="keyword"> const</span> QStringList<span class="operator"> &</span> relation<span class="operator"> =</span> QStringList<span class="operator">(),</span> QSqlDatabase<span class="operator"> *</span> pDatabase<span class="operator"> =</span> NULL<span class="operator">);</span><span class="keyword">
|
||
virtual</span> QSqlError qxFetchAll<span class="operator">(</span>qx<span class="operator">::</span>IxCollection<span class="operator"> &</span> list<span class="operator">,</span><span class="keyword"> const</span> QStringList<span class="operator"> &</span> columns<span class="operator"> =</span> QStringList<span class="operator">(),</span><span class="keyword"> const</span> QStringList<span class="operator"> &</span> relation<span class="operator"> =</span> QStringList<span class="operator">(),</span> QSqlDatabase<span class="operator"> *</span> pDatabase<span class="operator"> =</span> NULL<span class="operator">);</span><span class="keyword">
|
||
virtual</span> QSqlError qxFetchByQuery<span class="operator">(</span><span class="keyword">const</span> qx<span class="operator">::</span>QxSqlQuery<span class="operator"> &</span> query<span class="operator">,</span> qx<span class="operator">::</span>IxCollection<span class="operator"> &</span> list<span class="operator">,</span><span class="keyword"> const</span> QStringList<span class="operator"> &</span> columns<span class="operator"> =</span> QStringList<span class="operator">(),</span><span class="keyword"> const</span> QStringList<span class="operator"> &</span> relation<span class="operator"> =</span> QStringList<span class="operator">(),</span> QSqlDatabase<span class="operator"> *</span> pDatabase<span class="operator"> =</span> NULL<span class="operator">);</span><span class="keyword">
|
||
virtual</span> QSqlError qxInsert<span class="operator">(</span><span class="keyword">const</span> QStringList<span class="operator"> &</span> relation<span class="operator"> =</span> QStringList<span class="operator">(),</span> QSqlDatabase<span class="operator"> *</span> pDatabase<span class="operator"> =</span> NULL<span class="operator">);</span><span class="keyword">
|
||
virtual</span> QSqlError qxUpdate<span class="operator">(</span><span class="keyword">const</span> qx<span class="operator">::</span>QxSqlQuery<span class="operator"> &</span> query<span class="operator"> =</span> qx<span class="operator">::</span>QxSqlQuery<span class="operator">(),</span><span class="keyword"> const</span> QStringList<span class="operator"> &</span> columns<span class="operator"> =</span> QStringList<span class="operator">(),</span><span class="keyword"> const</span> QStringList<span class="operator"> &</span> relation<span class="operator"> =</span> QStringList<span class="operator">(),</span> QSqlDatabase<span class="operator"> *</span> pDatabase<span class="operator"> =</span> NULL<span class="operator">);</span><span class="keyword">
|
||
virtual</span> QSqlError qxSave<span class="operator">(</span><span class="keyword">const</span> QStringList<span class="operator"> &</span> relation<span class="operator"> =</span> QStringList<span class="operator">(),</span> QSqlDatabase<span class="operator"> *</span> pDatabase<span class="operator"> =</span> NULL<span class="operator">);</span><span class="keyword">
|
||
virtual</span> QSqlError qxDeleteById<span class="operator">(</span><span class="keyword">const</span> QVariant<span class="operator"> &</span> id<span class="operator"> =</span> QVariant<span class="operator">(),</span> QSqlDatabase<span class="operator"> *</span> pDatabase<span class="operator"> =</span> NULL<span class="operator">);</span><span class="keyword">
|
||
virtual</span> QSqlError qxDeleteAll<span class="operator">(</span>QSqlDatabase<span class="operator"> *</span> pDatabase<span class="operator"> =</span> NULL<span class="operator">);</span><span class="keyword">
|
||
virtual</span> QSqlError qxDeleteByQuery<span class="operator">(</span><span class="keyword">const</span> qx<span class="operator">::</span>QxSqlQuery<span class="operator"> &</span> query<span class="operator">,</span> QSqlDatabase<span class="operator"> *</span> pDatabase<span class="operator"> =</span> NULL<span class="operator">);</span><span class="keyword">
|
||
virtual</span> QSqlError qxDestroyById<span class="operator">(</span><span class="keyword">const</span> QVariant<span class="operator"> &</span> id<span class="operator"> =</span> QVariant<span class="operator">(),</span> QSqlDatabase<span class="operator"> *</span> pDatabase<span class="operator"> =</span> NULL<span class="operator">);</span><span class="keyword">
|
||
virtual</span> QSqlError qxDestroyAll<span class="operator">(</span>QSqlDatabase<span class="operator"> *</span> pDatabase<span class="operator"> =</span> NULL<span class="operator">);</span><span class="keyword">
|
||
virtual</span> QSqlError qxDestroyByQuery<span class="operator">(</span><span class="keyword">const</span> qx<span class="operator">::</span>QxSqlQuery<span class="operator"> &</span> query<span class="operator">,</span> QSqlDatabase<span class="operator"> *</span> pDatabase<span class="operator"> =</span> NULL<span class="operator">);</span><span class="keyword">
|
||
virtual</span> qx_bool qxExist<span class="operator">(</span><span class="keyword">const</span> QVariant<span class="operator"> &</span> id<span class="operator"> =</span> QVariant<span class="operator">(),</span> QSqlDatabase<span class="operator"> *</span> pDatabase<span class="operator"> =</span> NULL<span class="operator">);</span><span class="keyword">
|
||
virtual</span> qx<span class="operator">::</span>QxInvalidValueX qxValidate<span class="operator">(</span><span class="keyword">const</span> QStringList<span class="operator"> &</span> groups<span class="operator"> =</span> QStringList<span class="operator">());</span><span class="keyword">
|
||
virtual</span> qx<span class="operator">::</span>IxPersistableCollection_ptr qxNewPersistableCollection<span class="operator">()</span><span class="keyword"> const</span><span class="operator">;</span><span class="keyword">
|
||
virtual</span> qx<span class="operator">::</span>IxClass<span class="operator"> *</span> qxClass<span class="operator">()</span><span class="keyword"> const</span><span class="operator">;</span></pre>
|
||
</div>
|
||
<br>
|
||
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"><</span>qx<span class="operator">::</span>IxPersistable<span class="operator"> *></span> lst<span class="operator"> = ...;</span>
|
||
foreach<span class="operator">(</span>qx<span class="operator">::</span>IxPersistable<span class="operator"> *</span> p<span class="operator">,</span> lst<span class="operator">)
|
||
{</span>
|
||
QSqlError daoError<span class="operator"> =</span> p<span class="operator">-></span>qxSave<span class="operator">();</span><span class="flow">
|
||
if</span><span class="operator"> (</span>daoError<span class="operator">.</span>isValid<span class="operator">()) {</span><span class="comment"> /* an error occured */</span><span class="operator"> }</span><span class="comment">
|
||
// etc...
|
||
</span><span class="operator">}</span></pre>
|
||
</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
<br>
|
||
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"><</span>blog<span class="operator">></span> blog_ptr<span class="operator">;</span><span class="keyword">
|
||
typedef</span> std<span class="operator">::</span>vector<span class="operator"><</span>blog_ptr<span class="operator">></span> list_blog<span class="operator">;</span><span class="comment">
|
||
// -- enum
|
||
</span><span class="keyword"> enum</span> enum_sex<span class="operator"> {</span> male<span class="operator">,</span> female<span class="operator">,</span> unknown<span class="operator"> };</span><span class="comment">
|
||
// -- 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"><</span>author<span class="operator">></span> author_ptr<span class="operator">;</span><span class="keyword">
|
||
typedef</span> qx<span class="operator">::</span>QxCollection<span class="operator"><</span>QString<span class="operator">,</span> author_ptr<span class="operator">></span> list_author<span class="operator">;</span><span class="pre">
|
||
|
||
#endif <span class="comment">// _QX_BLOG_AUTHOR_H_</span>
|
||
</span></pre>
|
||
</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
<br>
|
||
<table border="1" bgcolor="#FFFFFF">
|
||
<col>
|
||
<tbody>
|
||
<tr>
|
||
<td title="author.cpp">
|
||
<pre><span class="pre">#include <span class="string">"../include/precompiled.h"</span>
|
||
|
||
#include <span class="string">"../include/author.h"</span>
|
||
#include <span class="string">"../include/blog.h"</span>
|
||
|
||
#include <span class="string"><QxOrm_Impl.h></span>
|
||
</span>
|
||
QX_REGISTER_CPP_QX_BLOG<span class="operator">(</span>author<span class="operator">)</span>
|
||
<font style="background-color:yellow"><b>QX_PERSISTABLE_CPP(author)</b></font>
|
||
|
||
<span class="keyword">namespace</span> qx<span class="operator"> {</span><span class="keyword">
|
||
template</span><span class="operator"> <></span><span class="type"> void</span> register_class<span class="operator">(</span>QxClass<span class="operator"><</span>author<span class="operator">> &</span> t<span class="operator">)
|
||
{</span>
|
||
t<span class="operator">.</span>id<span class="operator">(&</span> author<span class="operator">::</span>m_id<span class="operator">,</span><span class="string"> "author_id"</span><span class="operator">);</span>
|
||
|
||
t<span class="operator">.</span>data<span class="operator">(&</span> author<span class="operator">::</span>m_name<span class="operator">,</span><span class="string"> "name"</span><span class="operator">);</span>
|
||
t<span class="operator">.</span>data<span class="operator">(&</span> author<span class="operator">::</span>m_birthdate<span class="operator">,</span><span class="string"> "birthdate"</span><span class="operator">);</span>
|
||
t<span class="operator">.</span>data<span class="operator">(&</span> author<span class="operator">::</span>m_sex<span class="operator">,</span><span class="string"> "sex"</span><span class="operator">);</span>
|
||
|
||
t<span class="operator">.</span>relationOneToMany<span class="operator">(&</span> author<span class="operator">::</span>m_blogX<span class="operator">,</span><span class="string"> "list_blog"</span><span class="operator">,</span><span class="string"> "author_id"</span><span class="operator">);</span>
|
||
|
||
t<span class="operator">.</span>fct_0<span class="operator"><</span><span class="type">int</span><span class="operator">>(&</span> author<span class="operator">::</span>age<span class="operator">,</span><span class="string"> "age"</span><span class="operator">);
|
||
}}</span><span class="type">
|
||
|
||
int</span> author<span class="operator">::</span>age<span class="operator">()</span><span class="keyword"> const</span><span class="operator">
|
||
{</span><span class="flow">
|
||
if</span><span class="operator"> (!</span> m_birthdate<span class="operator">.</span>isValid<span class="operator">()) {</span><span class="flow"> return</span><span class="operator"> -</span><span class="int">1</span><span class="operator">; }</span><span class="flow">
|
||
return</span><span class="operator"> (</span>QDate<span class="operator">::</span>currentDate<span class="operator">().</span>year<span class="operator">() -</span> m_birthdate<span class="operator">.</span>year<span class="operator">());
|
||
}</span>
|
||
</pre>
|
||
</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
<br>
|
||
<b>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<T></i> setting function ;
|
||
</li>
|
||
<li>"<i>*</i>" keyword means "<i>fetch all relationships defined into
|
||
<i>qx::register_class<T></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<T></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->list_blog->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"> <<</span><span class="string"> "author_id->list_blog->list_comment"</span><span class="operator">;</span>
|
||
relation<span class="operator"> <<</span><span class="string"> "author_id->list_blog->list_category"</span><span class="operator">;</span>
|
||
relation<span class="operator"> <<</span><span class="string"> "list_comment"</span><span class="operator">;</span>
|
||
relation<span class="operator"> <<</span><span class="string"> "list_category"</span><span class="operator">;</span>
|
||
QSqlError daoError<span class="operator"> =</span> qx<span class="operator">::</span>dao<span class="operator">::</span>fetch_by_id_with_relation<span class="operator">(</span>relation<span class="operator">,</span> my_blog<span class="operator">);</span></pre>
|
||
</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
<br>
|
||
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">"*->*->*"</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<T>()</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<T>()</a> function is a <i>template</i> function : T
|
||
type must be registered in QxOrm context (<i>qx::register_class<T></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">() ></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"> &</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">((&</span> m_daoAsync<span class="operator">),</span> SIGNAL<span class="operator">(</span>queryFinished<span class="operator">(</span><span class="keyword">const</span> QSqlError<span class="operator"> &,</span> qx<span class="operator">::</span>dao<span class="operator">::</span>detail<span class="operator">::</span>QxDaoAsyncParams_ptr<span class="operator">)),</span><span class="keyword">
|
||
this</span><span class="operator">,</span> SLOT<span class="operator">(</span>onQueryFinished<span class="operator">(</span><span class="keyword">const</span> QSqlError<span class="operator"> &,</span> qx<span class="operator">::</span>dao<span class="operator">::</span>detail<span class="operator">::</span>QxDaoAsyncParams_ptr<span class="operator">)));</span><span class="comment">
|
||
//...
|
||
</span><span class="operator">}</span><span class="type">
|
||
|
||
void</span> MyWidget<span class="operator">::</span>onQueryFinished<span class="operator">(</span><span class="keyword">const</span> QSqlError<span class="operator"> &</span> daoError<span class="operator">,</span> qx<span class="operator">::</span>dao<span class="operator">::</span>detail<span class="operator">::</span>QxDaoAsyncParams_ptr pDaoParams<span class="operator">)
|
||
{</span><span class="flow">
|
||
if</span><span class="operator"> (!</span> pDaoParams<span class="operator">) {</span><span class="flow"> return</span><span class="operator">; }</span>
|
||
qx<span class="operator">::</span>QxSqlQuery query<span class="operator"> =</span> pDaoParams<span class="operator">-></span>query<span class="operator">;</span><span class="flow">
|
||
if</span><span class="operator"> (!</span> daoError<span class="operator">.</span>isValid<span class="operator">()) { ; }</span><span class="comment">
|
||
// If the async query is associated to a simple object, just use 'pDaoParams->pInstance' method
|
||
</span> qx<span class="operator">::</span>IxPersistable_ptr ptr<span class="operator"> =</span> pDaoParams<span class="operator">-></span>pInstance<span class="operator">;</span><span class="comment">
|
||
// If the async query is associated to a list of objects, just use 'pDaoParams->pListOfInstances' method
|
||
</span> qx<span class="operator">::</span>IxPersistableCollection_ptr lst<span class="operator"> =</span> pDaoParams<span class="operator">-></span>pListOfInstances<span class="operator">;</span><span class="comment">
|
||
//...
|
||
</span><span class="operator">}</span></pre>
|
||
</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
<br>
|
||
</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
<br><br>
|
||
<a name="faq_300"><u><b>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"><</span>author<span class="operator">>();</span>
|
||
pModel<span class="operator">-></span>qxFetchAll<span class="operator">();</span><span class="comment">
|
||
|
||
// Associate the model to a QTableView and display it
|
||
</span>QTableView tableView<span class="operator">;</span>
|
||
tableView<span class="operator">.</span>setModel<span class="operator">(</span>pModel<span class="operator">);</span>
|
||
tableView<span class="operator">.</span>show<span class="operator">();</span></pre>
|
||
</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
<br>
|
||
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"><</span>author<span class="operator">>();</span>
|
||
pModel<span class="operator">-></span>qxFetchAll<span class="operator">();</span><span class="comment">
|
||
|
||
// Associate the model to a QML view and display it
|
||
</span>QQuickView qmlView<span class="operator">;</span>
|
||
qmlView<span class="operator">.</span>rootContext<span class="operator">()-></span>setContextProperty<span class="operator">(</span><span class="string">"myModel"</span><span class="operator">,</span> pModel<span class="operator">);</span>
|
||
qmlView<span class="operator">.</span>setSource<span class="operator">(</span>QUrl<span class="operator">(</span><span class="string">"qrc:/documents/main.qml"</span><span class="operator">));</span>
|
||
qmlView<span class="operator">.</span>show<span class="operator">();</span></pre>
|
||
</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
<br>
|
||
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> |