QxOrm C++

Home Download Quick sample Tutorial Faq Link

QxOrm >> Faq Version courante : QxOrm 1.1.4 (LGPL) Version française du site Web site english version

Qu'est-ce que QxOrm ?

QxOrm est une librairie C++ de gestion de données développée par Lionel Marty, Ingénieur en développement logiciel depuis 2003.
QxOrm fournit de nombreuses fonctionnalités à partir d'une simple fonction de paramétrage :
  • persistance : communication avec de nombreuses bases de données (avec support des relations 1-1, 1-n, n-1 et n-n)
  • serialization des données (flux binaire et xml)
  • moteur de reflection pour accéder aux classes, attributs et invoquer des méthodes

Comment contacter QxOrm pour indiquer un bug ou poser une question ?

Si vous trouvez un bug ou si vous avez une question concernant le fonctionnement de la librairie QxOrm, vous pouvez envoyer un mail à : support@qxorm.com.
QxOrm est également disponible sur le site SourceForge : plate-forme d'hébergement de projets de développements de logiciels libres.
Un forum dédié à QxOrm est disponible en cliquant ici.


Quelles sont les bases de données prises en compte par QxOrm ?

QxOrm utilise le moteur QtSql de Qt basé sur un système de plugin.
Une liste détaillée des bases de données supportées est disponible sur le site de Qt en cliquant ici.
Le plugin ODBC (QODBC) assure une compatibilité avec de nombreuses bases de données.
Pour des performances optimales, il est possible d'utiliser un plugin spécifique à une base de données :
  • QMYSQL : MySQL
  • QPSQL : PostgreSQL (versions 7.3 and above)
  • QOCI : Oracle Call Interface Driver
  • QSQLITE : SQLite version 3
  • QDB2 : IBM DB2 (version 7.1 and above)
  • QIBASE : Borland InterBase
  • QTDS : Sybase Adaptive Server

Pourquoi QxOrm est dépendant de 2 librairies : boost et Qt ?

QxOrm utilise de nombreuses fonctionnalités disponibles dans les excellentes librairies boost et Qt.
De plus, ces 2 librairies sont utilisées dans de nombreux projets à la fois professionnels et open-source.
Il existe un grand nombre de forums, de tutoriaux, et toute une communauté pour répondre à toutes les problématiques que vous pourriez rencontrer.
L'objectif de QxOrm n'est pas de redévelopper des fonctionnalités qui existent déjà mais de fournir un outil performant d'accès aux bases de données comme il en existe dans d'autres langages (Java avec Hibernate, .Net avec NHibernate, Ruby, Python, etc...).

boost boost : de nombreux modules de la librairie boost font partie de la nouvelle norme C++.
C'est une librairie reconnue pour sa qualité, son code 'C++ moderne', sa documentation, sa portabilité, etc...
QxOrm utilise les fonctionnalités suivantes de boost : smart_pointer, serialization, type_traits, multi_index_container, unordered_container, any, tuple, foreach, function.
Il est conseillé d'installer et d'utiliser la dernière version de boost disponible à l'adresse suivante : http://www.boost.org/

Qt Qt : bibliothèque complète : IHM (QtGui), réseau (QtNetwork), XML (QtXml), base de données (QtSql), etc...
La documentation est excellente et le code C++ écrit à partir de cette bibliothèque est à la fois performant et simple de compréhension.
Depuis le rachat par Nokia et sa nouvelle licence LGPL, Qt est sans contexte la bibliothèque phare du moment.
QxOrm est compatible avec les principaux objets définis par Qt : QObject, QString, QDate, QTime, QDateTime, QList, QHash, QSharedPointer, QScopedPointer, etc...
Il est conseillé d'installer et d'utiliser la dernière version de Qt disponible à l'adresse suivante : http://qt.nokia.com/


Pourquoi QxOrm nécessite un en-tête précompilé (precompiled header) pour pouvoir être utilisé ?

QxOrm utilise les techniques de méta-programmation C++ pour fournir une grande partie de ses fonctionnalités.
Vous n'avez pas besoin de savoir utiliser la méta-programmation pour travailler avec la librairie QxOrm.
En effet, QxOrm se veut simple d'utilisation et un code C++ écrit avec Qt et QxOrm est facile à lire, donc facile à développer et à maintenir.

Cependant, la méta-programmation est couteuse en temps de compilation.
En utilisant un fichier precompiled.h, votre projet se compilera beaucoup plus vite.
Un autre avantage (et non des moindres) est que le fichier QxOrm.h regroupe les fonctionnalités de base des librairies boost et Qt.
Il n'est donc plus nécessaire d'écrire #include <QtCore/QString.h> pour utiliser la classe QString de Qt par exemple.
De même, pour utiliser les pointeurs intelligents de boost, il n'est plus nécessaire d'écrire #include <boost/shared_ptr.hpp>.


Est-il possible d'accélérer les temps de compilation de mon projet ?

Oui, si la serialization de vos données au format xml n'est pas utilisée dans votre projet, vous pouvez désactiver cette fonctionnalité.
Les temps de compilation seront alors réduits mais vous n'aurez plus accès au namespace qx::serialization:xml.
Pour désactiver la serialization xml, il faut ouvrir le fichier QxConfig.h et modifier la constante _QX_SERIALIZE_XML.
Une recompilation de la librairie QxOrm est nécessaire pour prendre en compte cette modification.

Une autre possibilité est d'utiliser les classes polymorphiques de la librairie boost::serialization (à la place des classes template).
Cette fonctionnalité réduit les temps de compilation ainsi que la taille de l'éxecutable généré.
En contre-partie, la vitesse d'exécution de votre programme sera réduite puisqu'une partie du travail effectué lors de la compilation devra être réalisé à l'exécution de votre application.
Pour activer cette fonctionnalité dans QxOrm, vous devez modifier la constante _QX_SERIALIZE_POLYMORPHIC du fichier QxConfig.h.
Attention : les fonctions de serialization seront alors accessibles depuis les namespace suivants : qx::serialization::polymorphic_binary, qx::serialization::polymorphic_text et qx::serialization::polymorphic_xml.
Une recompilation de la librairie QxOrm est nécessaire pour prendre en compte cette modification.


Pourquoi QxOrm fournit un nouveau type de container qx::QxCollection<Key, Value> ?

Il existe de nombreux container dans les librairies stl, boost et Qt.
Il est donc légitime de se poser cette question : à quoi sert qx::QxCollection<Key, Value> ?
qx::QxCollection<Key, Value> est un nouveau container (basé sur l'excellente librairie boost::multi_index_container) qui possède les fonctionnalités suivantes :
  • conserve l'ordre d'insertion des éléments dans la liste
  • accès rapide à un élément par son index : équivaut à std::vector<T> ou QList<T> par exemple
  • accès rapide à un élément par une clé (hash-map) : équivaut à QHash<Key, Value> ou boost::unordered_map<Key, Value> par exemple
  • fonctions de tri sur le type Key et sur le type Value
Remarque : qx::QxCollection<Key, Value> est compatible avec la macro foreach fournie par la librairie Qt ainsi que par la macro BOOST_FOREACH fournie par la librairie boost.
Cependant, chaque élément renvoyé par ces 2 macros correspond à un objet de type std::pair<Key, Value>.
Pour obtenir un résultat 'plus naturel' et plus lisible, il est conseillé d'utiliser la macro _foreach : cette macro utilise BOOST_FOREACH pour tous les container sauf pour qx::QxCollection<Key, Value>.
Dans ce cas, l'élément renvoyé correspond au type Value (voir par la suite l'exemple d'utilisation).
La macro _foreach est donc compatible avec tous les container (stl, Qt, boost, etc...) puisqu'elle utilise la macro BOOST_FOREACH.

Autre Remarque : qx::QxCollection<Key, Value> est particulièrement adapté pour recevoir des données issues d'une base de données.
En effet, ces données peuvent être triées (en utilisant ORDER BY dans une requête sql par exemple), il est donc important de conserver l'ordre d'insertion des éléments dans la liste.
De plus, chaque donnée issue d'une base de données possède un identifiant unique. Il est donc intéressant de pouvoir accéder à un élément en fonction de cet identifiant unique de manière extrèmement rapide (hash-map).

Exemple d'utilisation :
/* definition of drug class with 3 properties : code, name, description */
class drug { public: QString code; QString name; QString desc; };

/* smart pointer of drug */
typedef boost::shared_ptr<drug> drug_ptr;

/* collection of drugs by code */
qx::QxCollection<QString, drug_ptr> lstDrugs;

/* create 3 new drugs */
drug_ptr d1; d1.reset(new drug()); d1->code = "code1"; d1->name = "name1"; d1->desc = "desc1";
drug_ptr d2; d2.reset(new drug()); d2->code = "code2"; d2->name = "name2"; d2->desc = "desc2";
drug_ptr d3; d3.reset(new drug()); d3->code = "code3"; d3->name = "name3"; d3->desc = "desc3";

/* insert drugs into the collection */
lstDrugs.insert(d1->code, d1);
lstDrugs.insert(d2->code, d2);
lstDrugs.insert(d3->code, d3);

/* iterate with '_foreach' keyword */
_foreach(drug_ptr p, lstDrugs)
{ qDebug() << qPrintable(p->name) << " " << qPrintable(p->desc); }

/* iterate with 'for' keyword */
for (long l = 0; l < lstDrugs.count(); ++l)
{
   drug_ptr p = lstDrugs.getByIndex(l);
   QString code = lstDrugs.getKeyByIndex(l);
   qDebug() << qPrintable(p->name) << " " << qPrintable(p->desc);
}

/* iterate with 'QxCollectionIterator' java style */
qx::QxCollectionIterator<QString, drug_ptr> itr(lstDrugs);
while (itr.next())
{
   QString code = itr.key();
   qDebug() << qPrintable(itr.value()->name) << " " << qPrintable(itr.value()->desc);
}

/* sort ascending by key and sort descending by value */
lstDrugs.sortByKey(true);
lstDrugs.sortByValue(false);

/* access drug by code */
drug_ptr p = lstDrugs.getByKey("code2");

/* access drug by index */
drug_ptr p = lstDrugs.getByIndex(2);

/* test if drug exists and if collection is empty */
bool bExist = lstDrugs.exist("code3");
bool bEmpty = lstDrugs.empty();

/* remove the second drug from collection */
lstDrugs.removeByIndex(2);

/* remove the drug with "code3" */
lstDrugs.removeByKey("code3");

/* clear the collection */
lstDrugs.clear();


Pourquoi QxOrm fournit un nouveau type de pointeur intelligent qx::dao::ptr<T> ?

QxOrm est compatible avec les pointeurs intelligents des librairies boost et Qt.
Le pointeur intelligent développé par QxOrm est basé sur QSharedPointer et apporte de nouvelles fonctionnalités s'il est utilisé avec les fonctions 'qx::dao::...'.
qx::dao::ptr<T> conserve automatiquement les valeurs issues de la base de données.
Il est ainsi possible de vérifier à tout moment si une instance d'objet a subi des modifications grâce à la méthode 'isDirty()' : cette méthode peut renvoyer la liste de toutes les propriétés ayant été modifiées.
qx::dao::ptr<T> peut également être utilisé par la fonction 'qx::dao::update_optimized()' pour mettre à jour en base de données uniquement les champs modifiés.
qx::dao::ptr<T> peut être utilisé avec un objet simple ou bien avec la plupart des containers : stl, boost, Qt et qx::QxCollection<Key, Value>.

Exemple d'utilisation :
   // Test 'isDirty()' method
   qx::dao::ptr<blog> blog_isdirty = qx::dao::ptr<blog>(new blog());
   blog_isdirty->m_id = blog_1->m_id;
   daoError = qx::dao::fetch_by_id(blog_isdirty);
   qAssert(! daoError.isValid() && ! blog_isdirty.isDirty());

   blog_isdirty->m_text = "blog property 'text' modified => blog is dirty !!!";
   QStringList lstDiff; bool bDirty = blog_isdirty.isDirty(lstDiff);
   qAssert(bDirty && (lstDiff.count() == 1) && (lstDiff.at(0) == "blog_text"));
   if (bDirty) { qDebug("[QxOrm] test dirty 1 : blog is dirty => '%s'", qPrintable(lstDiff.join("|"))); }

   // Update only property 'm_text' of 'blog_isdirty'
   daoError = qx::dao::update_optimized(blog_isdirty);
   qAssert(! daoError.isValid() && ! blog_isdirty.isDirty());
   qx::dump(blog_isdirty);

   // Test 'isDirty()' method with a container
   typedef qx::dao::ptr< QList<author_ptr> > type_lst_author_test_is_dirty;

   type_lst_author_test_is_dirty container_isdirty = type_lst_author_test_is_dirty(new QList<author_ptr>());
   daoError = qx::dao::fetch_all(container_isdirty);
   qAssert(! daoError.isValid() && ! container_isdirty.isDirty() && (container_isdirty->count() == 3));

   author_ptr author_ptr_dirty = container_isdirty->at(1);
   author_ptr_dirty->m_name = "author name modified at index 1 => container is dirty !!!";
   bDirty = container_isdirty.isDirty(lstDiff);
   qAssert(bDirty && (lstDiff.count() == 1));
   if (bDirty) { qDebug("[QxOrm] test dirty 2 : container is dirty => '%s'", qPrintable(lstDiff.join("|"))); }

   author_ptr_dirty = container_isdirty->at(2);
   author_ptr_dirty->m_birthdate = QDate(1998, 03, 06);
   bDirty = container_isdirty.isDirty(lstDiff);
   qAssert(bDirty && (lstDiff.count() == 2));
   if (bDirty) { qDebug("[QxOrm] test dirty 3 : container is dirty => '%s'", qPrintable(lstDiff.join("|"))); }

   // Update only property 'm_name' at position 1, only property 'm_birthdate' at position 2 and nothing at position 0
   daoError = qx::dao::update_optimized(container_isdirty);
   qAssert(! daoError.isValid() && ! container_isdirty.isDirty());
   qx::dump(container_isdirty);

   // Fetch only property 'm_dt_creation' of blog
   QStringList lstColumns = QStringList() << "date_creation";
   list_blog lst_blog_with_only_date_creation;
   daoError = qx::dao::fetch_all(lst_blog_with_only_date_creation, NULL, lstColumns);
   qAssert(! daoError.isValid() && (lst_blog_with_only_date_creation.size() > 0));

   if ((lst_blog_with_only_date_creation.size() > 0) && (lst_blog_with_only_date_creation[0] != NULL))
   { qAssert(lst_blog_with_only_date_creation[0]->m_text.isEmpty()); }

   qx::dump(lst_blog_with_only_date_creation);


Faut-il utiliser QString ou std::string ?

QxOrm conseille d'utiliser la classe QString pour la gestion des chaînes de caractères.
Même si boost fournit de nombreuses fonctionnalités avec son module boost::string_algo, la classe QString est plus simple à utiliser et surtout prend en charge automatiquement les différents formats : Ascii, Utf8, Utf16, etc...
Cependant, QxOrm est compatible avec std::string et std::wstring si vous préférez utiliser ce type de chaîne de caractères.


Faut-il utiliser les pointeurs intelligents smart-pointer ?

QxOrm conseille fortement d'utiliser les pointeurs intelligents de boost ou Qt.
Le langage C++ ne possède pas de Garbage Collector comme Java ou C# par exemple.
L'utilisation des smart-pointer simplifie énormément la gestion de la mémoire en C++.
L'idéal dans un programme C++ est de n'avoir aucun appel à delete ou delete[].
De plus, les smart-pointer font partie de la nouvelle norme C++ : C++1x.
Il est donc essentiel aujourd'hui de connaître les classes suivantes :


La clé primaire est de type long par défaut. Est-il possible d'utiliser une clé de type QString ou autre ?

Il est possible de définir un identifiant unique de type QString ou autre avec la librairie QxOrm.
Par défaut, l'identifiant unique est de type long.
Pour indiquer qu'une classe a un identifiant unique de type QString ou autre, il faut spécialiser le template qx::trait::get_primary_key.
Pour simplifier, vous pouvez utiliser la macro : QX_REGISTER_PRIMARY_KEY(myClass, QString).

Attention : la macro QX_REGISTER_PRIMARY_KEY doit être utilisée avant la macro QX_REGISTER_HPP_... dans la définition de votre classe, sinon une erreur de compilation se produit.


Comment définir une clé primaire sur plusieurs colonnes (composite key) ?

QxOrm supporte la notion de 'multi-columns primary key'.
L'identifiant de la classe doit être du type suivant :
* QPair ou std::pair pour définir 2 colonnes
* boost::tuple pour définir de 2 à 9 colonnes

Il est nécessaire d'utiliser la macro QX_REGISTER_PRIMARY_KEY() pour spécialiser le template et ainsi définir le type d'identifiant sur plusieurs colonnes.
La liste des noms des colonnes doit être de la forme suivante : 'column1|column2|column3|etc...'.

Exemple d'utilisation avec la classe 'author' du projet 'qxBlog_composite_key', cette classe possède un identifiant sur 3 colonnes :

#ifndef _QX_BLOG_AUTHOR_H_
#define _QX_BLOG_AUTHOR_H_

class blog;

class QX_BLOG_DLL_EXPORT author
{

   QX_REGISTER_FRIEND_CLASS(author)

public:

// -- composite key (multi-column primary key in database)
   typedef boost::tuple<QString, long, QString> type_composite_key;
   static QString str_composite_key() { return "author_id_0|author_id_1|author_id_2"; }

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

// -- enum
   enum enum_sex { male, female, unknown };

// -- properties
   type_composite_key   m_id;
   QString              m_name;
   QDate                m_birthdate;
   enum_sex             m_sex;
   list_blog            m_blogX;

// -- contructor, virtual destructor
   author() : m_id("", 0, ""), m_sex(unknown) { ; }
   virtual ~author() { ; }

// -- methods
   int age() const;

// -- methods "get" to composite key
   type_composite_key getId() const    { return m_id; }
   QString getId_0() const             { return boost::tuples::get<0>(m_id); }
   long getId_1() const                { return boost::tuples::get<1>(m_id); }
   QString getId_2() const             { return boost::tuples::get<2>(m_id); }

// -- methods "set" to composite key
   void setId_0(const QString & s)     { boost::tuples::get<0>(m_id) = s; }
   void setId_1(long l)                { boost::tuples::get<1>(m_id) = l; }
   void setId_2(const QString & s)     { boost::tuples::get<2>(m_id) = s; }

};

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

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

#endif // _QX_BLOG_AUTHOR_H_

#include "../include/precompiled.h"
#include "../include/author.h"
#include "../include/blog.h"
#include <QxMemLeak.h>

QX_REGISTER_CPP_QX_BLOG(author)

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

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

   t.relationOneToMany(& author::m_blogX, blog::str_composite_key(), author::str_composite_key());

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

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


Comment activer/désactiver le module QxMemLeak pour la détection automatique des fuites mémoires ?

Le module QxMemLeak permet une détection rapide des fuites mémoire en mode Debug une fois l'exécution du programme terminée (avec indication du fichier et de la ligne => style MFC de Microsoft).
Ce module a été développé par Wu Yongwei et a subi quelques modifications pour être intégré dans QxOrm.
Si un autre outil est déjà utilisé dans vos projets (Valgrind par exemple), cette fonctionnalité ne doit pas être activée.
Pour activer/désactiver le module QxMemLeak, il suffit de modifier la constante _QX_USE_MEM_LEAK_DETECTION définie dans le fichier QxConfig.h.
Une recompilation de la librairie QxOrm est nécessaire pour prendre en compte cette modification.


Comment gérer la notion d'héritage avec la base de données ?

On retrouve généralement dans les différents outils de type ORM 3 différentes stratégies pour gérer la notion d'héritage avec la base de données :
* Single Table Inheritance
* Class Table Inheritance
* Concrete Table Inheritance

QxOrm utilise par défaut la stratégie Concrete Table Inheritance (les autres stratégies ne sont pas fonctionnelles à l'heure actuelle).
De nombreux tutoriaux et forums sont disponibles sur internet pour plus de détails sur cette notion d'héritage.
Un exemple d'utilisation avec une classe de base se trouve dans le dossier ./test/dll2/ avec la classe BaseClassTrigger.


Comment utiliser les Trigger ?

Les Trigger de QxOrm permettent d'effectuer divers traitements avant et/ou après une insertion, une mise à jour ou bien une suppression dans la base de données.
Un exemple d'utilisation se trouve dans le dossier ./test/dll2/ avec la classe BaseClassTrigger.
Cette classe contient 5 propriétés : m_id, m_dateCreation, m_dateModification, m_userCreation et m_userModification.
Ces propriétés se mettront à jour automatiquement pour chaque classe héritant de BaseClassTrigger (cf. les classes Foo et Bar du même projet).
Il est nécessaire de spécialiser le template 'QxDao_Trigger' pour profiter de cette fonctionnalité.

#ifndef _QX_BASE_CLASS_TRIGGER_H_
#define _QX_BASE_CLASS_TRIGGER_H_

class QX_DLL2_EXPORT BaseClassTrigger
{

   QX_REGISTER_FRIEND_CLASS(BaseClassTrigger)

protected:

   long        m_id;
   QDateTime   m_dateCreation;
   QDateTime   m_dateModification;
   QString     m_userCreation;
   QString     m_userModification;

public:

   BaseClassTrigger() : m_id(0)  { ; }
   virtual ~BaseClassTrigger()   { ; }

   long getId() const                     { return m_id; }
   QDateTime getDateCreation() const      { return m_dateCreation; }
   QDateTime getDateModification() const  { return m_dateModification; }
   QString getUserCreation() const        { return m_userCreation; }
   QString getUserModification() const    { return m_userModification; }

   void setId(long l)                              { m_id = l; }
   void setDateCreation(const QDateTime & dt)      { m_dateCreation = dt; }
   void setDateModification(const QDateTime & dt)  { m_dateModification = dt; }
   void setUserCreation(const QString & s)         { m_userCreation = s; }
   void setUserModification(const QString & s)     { m_userModification = s; }

   void onBeforeInsert(qx::dao::detail::IxDao_Helper * dao);
   void onBeforeUpdate(qx::dao::detail::IxDao_Helper * dao);

};

QX_REGISTER_HPP_QX_DLL2(BaseClassTrigger, qx::trait::no_base_class_defined, 0)

namespace qx {
namespace dao {
namespace detail {

template <>
struct QxDao_Trigger<BaseClassTrigger>
{

   static inline void onBeforeInsert(BaseClassTrigger * t, qx::dao::detail::IxDao_Helper * dao)
   { if (t) { t->onBeforeInsert(dao); } }
   static inline void onBeforeUpdate(BaseClassTrigger * t, qx::dao::detail::IxDao_Helper * dao)
   { if (t) { t->onBeforeUpdate(dao); } }
   static inline void onBeforeDelete(BaseClassTrigger * t, qx::dao::detail::IxDao_Helper * dao)
   { Q_UNUSED(t); Q_UNUSED(dao); }
   static inline void onAfterInsert(BaseClassTrigger * t, qx::dao::detail::IxDao_Helper * dao)
   { Q_UNUSED(t); Q_UNUSED(dao); }
   static inline void onAfterUpdate(BaseClassTrigger * t, qx::dao::detail::IxDao_Helper * dao)
   { Q_UNUSED(t); Q_UNUSED(dao); }
   static inline void onAfterDelete(BaseClassTrigger * t, qx::dao::detail::IxDao_Helper * dao)
   { Q_UNUSED(t); Q_UNUSED(dao); }

};

} // namespace detail
} // namespace dao
} // namespace qx

#endif // _QX_BASE_CLASS_TRIGGER_H_

#include "../include/precompiled.h"
#include "../include/BaseClassTrigger.h"
#include <QxMemLeak.h>

QX_REGISTER_CPP_QX_DLL2(BaseClassTrigger)

namespace qx {
template <> void register_class(QxClass<BaseClassTrigger> & t)
{
   IxDataMember * pData = NULL;

   pData = t.id(& BaseClassTrigger::m_id, "id");

   pData = t.data(& BaseClassTrigger::m_dateCreation, "date_creation");
   pData = t.data(& BaseClassTrigger::m_dateModification, "date_modification");
   pData = t.data(& BaseClassTrigger::m_userCreation, "user_creation");
   pData = t.data(& BaseClassTrigger::m_userModification, "user_modification");
}}

void BaseClassTrigger::onBeforeInsert(qx::dao::detail::IxDao_Helper * dao)
{
   Q_UNUSED(dao);
   m_dateCreation = QDateTime::currentDateTime();
   m_dateModification = QDateTime::currentDateTime();
   m_userCreation = "current_user_1";
   m_userModification = "current_user_1";
}

void BaseClassTrigger::onBeforeUpdate(qx::dao::detail::IxDao_Helper * dao)
{
   Q_UNUSED(dao);
   m_dateModification = QDateTime::currentDateTime();
   m_userModification = "current_user_2";
}




QxOrm