QxOrm is a C++ library designed to provide Object Relational Mapping (ORM) feature to C++ users.
With a simple C++ setting function by class (like Hibernate XML mapping file), you will have access to the following features:
- Persistence: Communication with a lot of databases (with 1-1, 1-n, n-1 and n-n relationships)
- Serialization: Binary and XML format
- Reflection: Access to classes definitions, retrieve properties and call classes methods
QxOrm aims to simplify C++ development and provides a lot of functionalities. Here is a list of advantages of QxOrm:
- Non intrusive: The C++ setting function doesn't modify class definition, QxOrm can be used in existing projects
- No code generation
- No XML mapping file
- Classes don't need to inherit from a 'super object'
- Template meta-programming: No macro hack
- Works with Visual C++ 2008 or 2010 on Windows, GCC 4.4.1 on Linux and MinGW on Windows (other platforms will be tested soon: Mac, phones...)
- Only one file <QxOrm.h> to include in precompiled-header (need precompiled-header file to reduce compilation times)
Before you install and compile QxOrm, you need the following libraries: boost (from version 1.38) and Qt (from version 4.5.0).
QxOrm library uses the following syntax for C++ source code:
- All classes, functions, properties, etc. are defined under namespace qx
- All macros of
QxOrm library start with QX_...
- All
abstract classes (or interfaces) start with Ix (for example IxFactory is an interface to create an instance of object)
- Other classes start with Qx (for example
QxDataMember)
- Containers of objects end with X (for example
QxDataMemberX is a list of QxDataMember)
- Functions to interact with databases are under namespace qx::dao (for example
qx::dao::fetch_by_id())
- Functions to serialize are under namespace qx::serialization (for example
qx::serialization::xml::to_file())
- The reflection engine can be used with qx::QxClassX (for example
qx::QxClassX::invoke() to call a class method)
- All traits classes are under namespace qx::trait (for example
qx::trait::is_smart_ptr<T>)
Quick sample step by step:
- drug.h file: Drug class definition with 3 properties : id, name and description
- drug.cpp file: 'setting function' implementation : void qx::register_class()
- main.cpp file: Basic functionalities of QxOrm library with drug class
- Execute program and trace output debug
- ./export_drugs.xml file created by the program
* ------------------------------------------------------------------------------------------
* 1- drug.h file : drug class definition with 3 properties : id, name and description
* ------------------------------------------------------------------------------------------
#ifndef _CLASS_DRUG_H_
#define _CLASS_DRUG_H_
class drug
{
public:
long id;
QString name;
QString description;
drug() : id(0) { ; }
virtual ~drug() { ; }
};
QX_REGISTER_HPP_MY_TEST_EXE(drug, qx::trait::no_base_class_defined, 1)
#endif
* ------------------------------------------------------------------------------------------
* 2- drug.cpp file : 'setting function' implementation : void qx::register_class()
* ------------------------------------------------------------------------------------------
#include "precompiled.h" // Precompiled-header with '#include <QxOrm.h>'
#include "drug.h" // Class definition 'drug'
#include <QxMemLeak.h> // Automatic memory leak detection
QX_REGISTER_CPP_MY_TEST_EXE(drug)
namespace qx {
template <> void register_class(QxClass<drug> & t)
{
t.id(& drug::id, "id"); t.data(& drug::name, "name", 1); t.data(& drug::description, "desc"); }}
* ------------------------------------------------------------------------------------------
* 3- main.cpp file : basic functionalities of QxOrm library with drug class
* ------------------------------------------------------------------------------------------
#include "precompiled.h"
#include "drug.h"
#include <QxMemLeak.h>
int main(int argc, char * argv[])
{
QApplication app(argc, argv);
typedef boost::shared_ptr<drug> drug_ptr;
drug_ptr d1; d1.reset(new drug()); d1->name = "name1"; d1->description = "desc1";
drug_ptr d2; d2.reset(new drug()); d2->name = "name2"; d2->description = "desc2";
drug_ptr d3; d3.reset(new drug()); d3->name = "name3"; d3->description = "desc3";
typedef std::vector<drug_ptr> type_lst_drug;
type_lst_drug lst_drug;
lst_drug.push_back(d1);
lst_drug.push_back(d2);
lst_drug.push_back(d3);
qx::QxSqlDatabase::getSingleton()->setDriverName("QSQLITE");
qx::QxSqlDatabase::getSingleton()->setDatabaseName("./test_qxorm.db");
qx::QxSqlDatabase::getSingleton()->setHostName("localhost");
qx::QxSqlDatabase::getSingleton()->setUserName("root");
qx::QxSqlDatabase::getSingleton()->setPassword("");
QSqlError daoError = qx::dao::create_table<drug>();
daoError = qx::dao::insert(lst_drug);
d2->name = "name2 modified";
d2->description = "desc2 modified";
daoError = qx::dao::update(d2);
daoError = qx::dao::delete_by_id(d1);
long lDrugCount = qx::dao::count<drug>();
drug_ptr d_tmp; d_tmp.reset(new drug());
d_tmp->id = 3;
daoError = qx::dao::fetch_by_id(d_tmp);
qx::serialization::xml::to_file(lst_drug, "./export_drugs.xml");
type_lst_drug lst_drug_tmp;
qx::serialization::xml::from_file(lst_drug_tmp, "./export_drugs.xml");
drug_ptr d_clone = qx::clone(* d1);
boost::any d_any = qx::create("drug");
qx::cache::set("drugs", lst_drug);
qx::cache::clear();
drug * pDummy = new drug();
return 0;
}
*-------------------------------------------------------------------------
* 4- execute program and trace output debug
* -------------------------------------------------------------------------
[QxOrm] qx::QxSqlDatabase : create new database connection in thread '3616'
with key '{d315250c-b5c9-46e0-9402-f800368a6673}'
[QxOrm] sql query (78 ms) : CREATE TABLE drug
(id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, name TEXT, desc TEXT)
[QxOrm] sql query (63 ms) : INSERT INTO drug (name, desc) VALUES (:name, :desc)
[QxOrm] sql query (62 ms) : UPDATE drug SET id = :id,
name = :name, desc = :desc WHERE id = :id_bis
[QxOrm] sql query (63 ms) : DELETE FROM drug WHERE id = :id
[QxOrm] sql query (0 ms) : SELECT COUNT(*) FROM drug
[QxOrm] sql query (0 ms) : SELECT drug.id AS drug_id_0,
drug.name AS drug_name_0, drug.desc AS
drug_desc_0 FROM drug WHERE drug_id_0 = :id
[QxOrm] Leaked object at 0xf52ad8 (size 16, src\main.cpp:74)
[QxOrm] **** 1 memory leaks found ****
* ------------------------------------------------------------------------------
* 5- ./export_drugs.xml file created by the program
* ------------------------------------------------------------------------------
In this tutorial, we will see a lot of functionalities of QxOrm library with the creation of a C++ project: qxBlog - blog management in C++.
qxBlog tutorial step by step:
- qxBlog project - blog management in C++
- All files in qxBlog project
- qxBlog.pro file
- export.h file
- precompiled.h file
- author.h and author.cpp (relationship one-to-many)
- comment.h and comment.cpp (relationship many-to-one)
- category.h and category.cpp (relationship many-to-many)
- blog.h and blog.cpp (relationship one-to-many, many-to-one and many-to-many)
- main.cpp file
- Relationship one-to-one with person class
1- qxBlog project - blog management in C++
- blog: 1 blog is written by 1 author, can have many comments and can be put inside many categories
- author: 1 author can write many blogs
- comment: 1 comment belongs to 1 blog
- category: 1 category contains many blogs
2- All files in qxBlog project
./qxBlog/ ./qxBlog/qxBlog.pro ./qxBlog/qxBlog.sqlite |
./qxBlog/include/precompiled.h ./qxBlog/include/export.h ./qxBlog/include/author.h ./qxBlog/include/blog.h ./qxBlog/include/category.h ./qxBlog/include/comment.h |
./qxBlog/src/author.cpp ./qxBlog/src/blog.cpp ./qxBlog/src/category.cpp ./qxBlog/src/comment.cpp ./qxBlog/src/main.cpp |
Note: Tutorial source code is available in the folder ./test/qxBlog/ of your QxOrm directory.
qxBlog.sqlite file is the tutorial database in the format sqlite.
3- qxBlog.pro file:
This file is necessary to compile and build the project with the command qmake provided by Qt library.
The tool qmake is multi-platform, so qxBlog project can be compiled under Windows, Linux, Mac, etc...
The file qxBlog.pro contains the list of all files in the project (header + source) and all dependencies (QxOrm.pri file contains all dependencies with boost and Qt libraries).
qxBlog.pro contains an important constant (_BUILDING_QX_BLOG) to know if the project is compiling (cf. export.h and DLL mechanism under Windows to import or export functions, classes...).

4- export.h file
A Windows DLL needs this file to manage 'export/import' of classes, functions...
QxOrm uses the same mechanism to provide some functionalities: so the file export.h is necessary to all projects using QxOrm library.
Note: Quick resume of DLL mechanism under Windows:
- when a DLL is compiling, each class is exported
- when another DLL is compiling, each class of the first DLL needs to be imported to be used
#ifndef _QX_BLOG_EXPORT_H_
#define _QX_BLOG_EXPORT_H_
#ifdef _BUILDING_QX_BLOG
#define QX_BLOG_DLL_EXPORT QX_DLL_EXPORT_HELPER
#else #define QX_BLOG_DLL_EXPORT QX_DLL_IMPORT_HELPER
#endif
#ifdef _BUILDING_QX_BLOG
#define QX_REGISTER_HPP_QX_BLOG QX_REGISTER_HPP_EXPORT_DLL
#define QX_REGISTER_CPP_QX_BLOG QX_REGISTER_CPP_EXPORT_DLL
#else #define QX_REGISTER_HPP_QX_BLOG QX_REGISTER_HPP_IMPORT_DLL
#define QX_REGISTER_CPP_QX_BLOG QX_REGISTER_CPP_IMPORT_DLL
#endif
#endif
5- precompiled.h file:
Precompiled header file reduces compilation times of a C++ project.
QxOrm uses meta-programming concept to provide a lot of functionalities.
meta-programming is costly in compilation times, so your project will be compiled much more quickly with the file precompiled.h.
Last but not least, another advantage is that the file QxOrm.h includes the basic functionalities of libraries boost and Qt.
It is thus not necessary anymore to write #include <QtCore/QString.h> to use the class QString of Qt for example.
In the same way, there is no need anymore to write #include <boost/shared_ptr.hpp> to use smart pointers of boost library.
#ifndef _QX_BLOG_PRECOMPILED_HEADER_H_
#define _QX_BLOG_PRECOMPILED_HEADER_H_
#include <QxOrm.h>
#include "export.h"
#endif
6- author.h and author.cpp (relationship one-to-many)
1 author can write many blogs: We will see how to use relationship one-to-many.
In the database, there are 2 tables:

In the C++ source code, the properties of
author class belong to columns of
author table in the database.
So 1 instance of
author class in the C++ source code belongs to 1 row of
author table in the database.
This mechanism provides C++ source code easy to develop and to maintain.
We add 1 method to our author class: int age() to retrieve the age with the data returned by the database.
We define also 2 typedef: a smart-pointer to an object author (using boost library), and a list of author (using qx::QxCollection of QxOrm library).
author class needs an id of QString type (by default, QxOrm provides id of long type): we use the macro QX_REGISTER_PRIMARY_KEY(author, QString) to specialize the template.
#ifndef _QX_BLOG_AUTHOR_H_
#define _QX_BLOG_AUTHOR_H_
class blog;
class QX_BLOG_DLL_EXPORT author
{
public:
typedef boost::shared_ptr<blog> blog_ptr;
typedef std::vector<blog_ptr> list_blog;
enum enum_sex { male, female, unknown };
QString m_id;
QString m_name;
QDate m_birthdate;
enum_sex m_sex;
list_blog m_blogX;
author() : m_id("0"), m_sex(unknown) { ; }
virtual ~author() { ; }
int age() const;
};
QX_REGISTER_PRIMARY_KEY(author, QString)
QX_REGISTER_HPP_QX_BLOG(author, qx::trait::no_base_class_defined, 0)
typedef boost::shared_ptr<author> author_ptr;
typedef qx::QxCollection<QString, author_ptr> list_author;
#endif #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_id");
t.data(& author::m_name, "name");
t.data(& author::m_birthdate, "birthdate");
t.data(& author::m_sex, "sex");
t.relationOneToMany(& author::m_blogX, "list_blog", "author_id");
t.fct_0<int>(& author::age, "age");
}}
int author::age() const
{
if (! m_birthdate.isValid()) { return -1; }
return (QDate::currentDate().year() - m_birthdate.year());
}
7- comment.h and comment.cpp (relationship many-to-one)
1 comment belongs to 1 blog and 1 blog can contain many comments: we will see how to use relationship many-to-one.
In the database, there are 2 tables:
Like author class, we define 2 typedefs: a smart-pointer to a comment object (using boost library) and a list of comments (using Qt library).
#ifndef _QX_BLOG_COMMENT_H_
#define _QX_BLOG_COMMENT_H_
class blog;
class QX_BLOG_DLL_EXPORT comment
{
public:
typedef boost::shared_ptr<blog> blog_ptr;
long m_id;
QString m_text;
QDateTime m_dt_create;
blog_ptr m_blog;
comment() : m_id(0) { ; }
virtual ~comment() { ; }
};
QX_REGISTER_HPP_QX_BLOG(comment, qx::trait::no_base_class_defined, 0)
typedef boost::shared_ptr<comment> comment_ptr;
typedef QList<comment_ptr> list_comment;
#endif #include "../include/precompiled.h"
#include "../include/comment.h"
#include "../include/blog.h"
#include <QxMemLeak.h>
QX_REGISTER_CPP_QX_BLOG(comment)
namespace qx {
template <> void register_class(QxClass<comment> & t)
{
t.id(& comment::m_id, "comment_id");
t.data(& comment::m_text, "comment_text");
t.data(& comment::m_dt_create, "date_creation");
t.relationManyToOne(& comment::m_blog, "blog_id");
}}
8- category.h and category.cpp (relationship many-to-many) :
1 category contains many blogs and 1 blog can be put inside many categories: we will see how to use relationship many-to-many.
This kind of relationship needs a new table in the database to save the list of ids for each relationship.
So in the database, there are 3 tables:

Like
author class and
comment class, we define 2
typedefs: a
smart-pointer to a
category object (using
Qt library) and a list of
categories (using
QxOrm library).
#ifndef _QX_BLOG_CATEGORY_H_
#define _QX_BLOG_CATEGORY_H_
class blog;
class QX_BLOG_DLL_EXPORT category
{
public:
typedef boost::shared_ptr<blog> blog_ptr;
typedef qx::QxCollection<long, blog_ptr> list_blog;
long m_id;
QString m_name;
QString m_desc;
list_blog m_blogX;
category() : m_id(0) { ; }
virtual ~category() { ; }
};
QX_REGISTER_HPP_QX_BLOG(category, qx::trait::no_base_class_defined, 0)
typedef QSharedPointer<category> category_ptr;
typedef qx::QxCollection<long, category_ptr> list_category;
#endif #include "../include/precompiled.h"
#include "../include/category.h"
#include "../include/blog.h"
#include <QxMemLeak.h>
QX_REGISTER_CPP_QX_BLOG(category)
namespace qx {
template <> void register_class(QxClass<category> & t)
{
t.id(& category::m_id, "category_id");
t.data(& category::m_name, "name");
t.data(& category::m_desc, "description");
t.relationManyToMany(& category::m_blogX,
"list_blog", "category_blog", "category_id", "blog_id");
}}
9- blog.h and blog.cpp (relationship one-to-many, many-to-one and many-to-many):
1 blog is written by 1 author, can have many comments and can be put inside many categories.
So this class has 3 relationships: one-to-many, many-to-one et many-to-many.
Like other classes, we define 2 typedefs: a smart-pointer to a blog object (using boost library) and a list of blogs (using stl library).
#ifndef _QX_BLOG_BLOG_H_
#define _QX_BLOG_BLOG_H_
#include "author.h"
#include "comment.h"
#include "category.h"
class QX_BLOG_DLL_EXPORT blog
{
public:
long m_id;
QString m_text;
QDateTime m_dt_creation;
author_ptr m_author;
list_comment m_commentX;
list_category m_categoryX;
blog() : m_id(0) { ; }
virtual ~blog() { ; }
};
QX_REGISTER_HPP_QX_BLOG(blog, qx::trait::no_base_class_defined, 0)
typedef boost::shared_ptr<blog> blog_ptr;
typedef std::vector<blog_ptr> list_blog;
#endif #include "../include/precompiled.h"
#include "../include/blog.h"
#include <QxMemLeak.h>
QX_REGISTER_CPP_QX_BLOG(blog)
namespace qx {
template <> void register_class(QxClass<blog> & t)
{
t.id(& blog::m_id, "blog_id");
t.data(& blog::m_text, "blog_text");
t.data(& blog::m_dt_creation, "date_creation");
t.relationManyToOne(& blog::m_author, "author_id");
t.relationOneToMany(& blog::m_commentX, "list_comment", "blog_id");
t.relationManyToMany(& blog::m_categoryX,
"list_category", "category_blog", "blog_id", "category_id");
}}
10- main.cpp file
QxOrm can communicate with many databases (see the list of databases in Qt web site) => persistence.
QxOrm also provides 2 other important functionalities:
- Serialization: Binary and XML format
- Reflection: Access to classes definitions, retrieve properties and call classes methods
#include "../include/precompiled.h"
#include <QtGui/qapplication.h>
#include "../include/blog.h"
#include "../include/author.h"
#include "../include/comment.h"
#include "../include/category.h"
#include <QxMemLeak.h>
int main(int argc, char * argv[])
{
QApplication app(argc, argv);
qx::QxSqlDatabase::getSingleton()->setDriverName("QSQLITE");
qx::QxSqlDatabase::getSingleton()->setDatabaseName("./qxBlog.sqlite");
qx::QxSqlDatabase::getSingleton()->setHostName("localhost");
qx::QxSqlDatabase::getSingleton()->setUserName("root");
qx::QxSqlDatabase::getSingleton()->setPassword("");
QSqlError daoError = qx::dao::delete_all<author>();
daoError = qx::dao::delete_all<comment>();
daoError = qx::dao::delete_all<category>();
daoError = qx::dao::delete_all<blog>();
author_ptr author_1; author_1.reset(new author());
author_ptr author_2; author_2.reset(new author());
author_ptr author_3; author_3.reset(new author());
author_1->m_id = "author_id_1"; author_1->m_name = "author_1";
author_1->m_sex = author::male; author_1->m_birthdate = QDate::currentDate();
author_2->m_id = "author_id_2"; author_2->m_name = "author_2";
author_2->m_sex = author::female; author_2->m_birthdate = QDate::currentDate();
author_3->m_id = "author_id_3"; author_3->m_name = "author_3";
author_3->m_sex = author::female; author_3->m_birthdate = QDate::currentDate();
list_author authorX;
authorX.insert(author_1->m_id, author_1);
authorX.insert(author_2->m_id, author_2);
authorX.insert(author_3->m_id, author_3);
daoError = qx::dao::insert(authorX);
qAssert(qx::dao::count<author>() == 3);
author_ptr author_clone = qx::clone(* author_2);
qAssert(author_clone->m_id == "author_id_2");
qAssert(author_clone->m_sex == author::female);
qx::QxSqlQuery query("WHERE author.sex = :sex");
query.bind(":sex", author::female);
list_author list_of_female_author;
daoError = qx::dao::fetch_by_query(query, list_of_female_author);
qAssert(list_of_female_author.count() == 2);
qx::dump(list_of_female_author);
category_ptr category_1 = category_ptr(new category());
category_ptr category_2 = category_ptr(new category());
category_ptr category_3 = category_ptr(new category());
category_1->m_name = "category_1"; category_1->m_desc = "desc_1";
category_2->m_name = "category_2"; category_2->m_desc = "desc_2";
category_3->m_name = "category_3"; category_3->m_desc = "desc_3";
{
QSqlDatabase db = qx::QxSqlDatabase::getDatabase();
bool bCommit = db.transaction();
daoError = qx::dao::insert(category_1, (& db));
bCommit = (bCommit && ! daoError.isValid());
daoError = qx::dao::insert(category_2, (& db));
bCommit = (bCommit && ! daoError.isValid());
daoError = qx::dao::insert(category_3, (& db));
bCommit = (bCommit && ! daoError.isValid());
qAssert(bCommit);
qAssert(category_1->m_id != 0);
qAssert(category_2->m_id != 0);
qAssert(category_3->m_id != 0);
if (bCommit) { db.commit(); }
else { db.rollback(); }
}
boost::any blog_any = qx::create("blog");
blog_ptr blog_1 = boost::any_cast<blog_ptr>(blog_any);
blog_1->m_text = "blog_text_1";
blog_1->m_dt_creation = QDateTime::currentDateTime();
blog_1->m_author = author_1;
daoError = qx::dao::save(blog_1);
blog_1->m_text = "update blog_text_1";
blog_1->m_author = author_2;
daoError = qx::dao::save(blog_1);
comment_ptr comment_1; comment_1.reset(new comment());
comment_ptr comment_2; comment_2.reset(new comment());
comment_1->m_text = "comment_1 text";
comment_1->m_dt_create = QDateTime::currentDateTime();
comment_1->m_blog = blog_1;
comment_2->m_text = "comment_2 text";
comment_2->m_dt_create = QDateTime::currentDateTime();
comment_2->m_blog = blog_1;
daoError = qx::dao::insert(comment_1);
daoError = qx::dao::insert(comment_2);
qAssert(qx::dao::count<comment>() == 2);
blog_1->m_categoryX.insert(category_1->m_id, category_1);
blog_1->m_categoryX.insert(category_3->m_id, category_3);
daoError = qx::dao::save_with_relation("list_category", blog_1);
blog_ptr blog_tmp; blog_tmp.reset(new blog());
blog_tmp->m_id = blog_1->m_id;
daoError = qx::dao::fetch_by_id_with_all_relation(blog_tmp);
qAssert(blog_tmp->m_commentX.count() == 2);
qAssert(blog_tmp->m_categoryX.count() == 2);
qAssert(blog_tmp->m_text == "update blog_text_1");
qAssert(blog_tmp->m_author && blog_tmp->m_author->m_id == "author_id_2");
qx::dump(blog_tmp);
qx_bool bInvokeOk = qx::QxClassX::invoke("author", "age", author_1);
qAssert(bInvokeOk);
return 0;
}
Click here to see output debug trace after execution of qxBlog program...
Important note: QxOrm doesn't want to hide SQL query (by default, all SQL queries are displayed).
QxOrm cannot resolve all problems with SQL and databases, so it is sometimes necessary to use QtSql engine of Qt library to write your own SQL query or stored procedure.
11- relationship one-to-one with person class
QxOrm can also be used with relationship one-to-one.
We add to our project the class person (person.h and person.cpp files): 1 person is 1 author.
So person and author share the same id in the database: this is a relationship one-to-one.
There are 2 tables in the database:
Note: We add to person table the column mother_id. So we can retrieve the mother (of type person) belongs to 1 person: this is a relationship many-to-one on the same table person. Moreover, if 1 person is a mother, we can retrieve the list of children (of type person): this is a relationship one-to-many on the same table person.
Changes in version 1.2.5
- New license : go to download page of QxOrm website for more details
- Support Qt5
- New compiler supported : Clang (tested on Mac OS X)
- Now each QxOrm version will be tested in 32-bit and 64-bit mode
- Improve QxOrm introspection engine : possibility to register static class methods
- Improve QxService module : now it's easy to add an authentication process on server side
- New class qx::exception to get error code + error description with services methods throwing an exception
- New settings available in QxOrm.pri config file (whithout changing QxConfig.h file)
- Possibility to implement specifics database SQL functions overriding qx_query class
- Fix an issue when fetching multiple levels of relationship and NULL pointers
- Fix a bug with MS SQL Server database and update queries using auto-increment id
Changes in version 1.2.4
- New relationship engine to fetch easily many levels of relationships per query
- For more details about this new engine, goto the FAQ : 'How to use relationship engine to fetch datas from many tables ?'
- Add 2 functions : qx::dao::execute_query and qx::dao::call_query to call a stored procedure or a custom SQL query
- For more details about this new feature, goto the FAQ : 'How to execute a stored procedure or a custom SQL query ?'
- Add support for boost::optional type to manage NULL database value without using QVariant type
- New class : qx::QxDaoAsync to make easier to execute queries in asynchronous way (multi-thread)
- For more details about this new class, goto the FAQ : 'How to use qx::QxDaoAsync class to execute queries in asynchronous way (multi-thread) ?'
Changes in version 1.2.3
- New interface '
qx::IxPersistable' (abstract class) to simplify polymorphism using QxOrm library
- For more details about this new interface, goto the FAQ : 'How to use
qx::IxPersistable interface ?'
- New methods into '
qx::IxCollection' interface to iterate over each items without knowing its type
- New option into 'QxOrm.pri' file to build QxOrm library statically (see '
_QX_STATIC_BUILD' option)
- New triggers : '
qx::dao::on_before_fetch' and 'qx::dao::on_after_fetch' (for more details, goto the FAQ : 'How to define a Trigger with QxOrm ?')
- Add '
std::type_info' class information to introspection engine
- Some minor bugs fixed ('
qx::dao::sql_error' exception message, SQL query column alias, mutex, etc.)
Changes in version 1.2.2
- New module to provide a validation engine:
QxValidator module
- For more details about
QxValidator module, goto the FAQ of QxOrm library: 'How to use QxValidator module to automatically validate an instance ?'
- Fix last insert ID with PostgreSQL using '
RETURNING' keyword: fetch inserted ID instead of OID
- Improve SQL generator providing the good SQL type for all databases
- Add support for special database keywords using '[', ']' and '"' characters
Changes in version 1.2.1
- Improve '
qx::QxSqlQuery' class: new engine to build queries without writing SQL, for more details, see the FAQ 'How to build a query without writing SQL with the class qx::QxSqlQuery?'
- Improve '
qx::QxSession' class: provide persistent methods (CRUD) without using 'qx::dao::xxx' functions, for more details, see the FAQ 'How to use a session (qx::QxSession class) to automatically manage database transactions (using C++ RAII)?'
- Implement 'repository' pattern to provide a common interface for persistent methods (CRUD) with 3 new classes : '
qx::IxRepository', 'qx::QxRepository' and 'qx::QxRepositoryX'
- Possibility to serialize a
QVariant 'UserType' with serialization engine of QxOrm library
- Improve thread-safe '
qx::cache': add insertion date-time into the cache to verify that an element must be updated or not, for more details, see the FAQ 'How to use the cache (functions into namespace qx::cache) of QxOrm library ?'
- FAQ updated on
QxOrm website with now 28 questions and answers
Changes in version 1.1.9
- Possibility to register automatically Qt meta-properties (using
Q_PROPERTY macro) to QxOrm context without writing mapping function per class (void qx::register_class())
- Strong integration with Qt introspection/moc engine : for more details about this new feature, goto the FAQ 'How to register automatically Qt meta-properties to QxOrm context ?'
- Improve introspection/reflection engine: see the FAQ (How to use introspection engine (or reflection engine) of QxOrm library?) for more details
- Possibility to add meta-data (using a property bag) to introspection engine : see '
IxClass', 'IxDataMember' and 'IxFunction' classes for more details
- Add function '
qx::QxClassX::dumpSqlSchema()' to explain how to create your own SQL schema based on C++ classes
- New class '
qx::QxSimpleCrypt' to provide encryption/decryption (thanks very much to Andre Somers) : so it's now possible to store encrypted data into database without using an external library
- QxService module: new feature to encrypt/decrypt data before transferring it over network
Changes in version 1.1.8
- QxOrm library can now be used on Mac (thanks very much to Dominique Billet): see 'osx_build_all_debug.sh' and 'osx_build_all_release.sh' scripts to build QxOrm library and all samples in './test/' directory
- Add '
qx::QxSession' class : define a session to manage automatically database transactions (using C++ RAII), see the FAQ for more details
- Add '
qx::QxDateNeutral', 'qx::QxTimeNeutral' and 'qx::QxDateTimeNeutral' classes : helper classes to store date-time value into database under neutral format => cross database compatibility
Changes in version 1.1.7
- Added soft delete behavior: see the FAQ (How to define a soft delete behavior?) for more details about this new feature
- Added functions into namespace '
qx::dao' to update an element with a SQL condition: update_by_query, update_optimized_by_query, etc.
- Fixed a bug when
QVariant type is used for a property of a persistent class: so, it's now possible to insert NULL value into database
Changes in version 1.1.6
QxOrm library online documentation available: http://www.qxorm.com/doxygen/index.html
- Possibility to disable
QtGui dependency using compilation option in 'QxConfig.h' file: _QX_ENABLE_QT_GUI_DEPENDENCY
Possibility to disable QtNetwork dependency (so QxService module too) using compilation option in 'QxConfig.h' file: _QX_ENABLE_QT_NETWORK_DEPENDENCY
- Provided a new macro to register
abstract class into QxOrm context: QX_REGISTER_ABSTRACT_CLASS()
Changes in version 1.1.5
- New feature available: '
QxService' module to create C++ application server
- '
QxService' provides an easy and powerful way to create services and to transfer data over network
- New tutorial available to explain how '
QxService' module works
- New sample available at './test/qxClientServer' directory
QxOrm can be built with 'CONFIG += no_keywords' flag in '*.pro' files
- Bug fix with '
qx::dao::create_table<>' function and relation 'many-to-many'
QxOrm should now build fine with GCC <= 4.2
Changes in version 1.1.4
- New parameter in functions '
qx::dao::fetch_by_id', 'qx::dao::fetch_all', 'qx::dao::fetch_by_query' and 'qx::dao::update' to define a list of properties to fetch/update (by default, all properties are fetched/updated)
- Support multi-columns primary key (composite key): see sample './test/qxBlogCompositeKey/'
- Improved strategy of inheritance:
QxOrm supports 'Concrete Table Inheritance' strategy ('Concrete Table Inheritance' becomes default strategy)
- New smart-pointer '
qx::dao::ptr' based on Qt 'QSharedPointer' to provide 2 new features: 'is dirty' and 'update optimized'
- '
qx::dao::ptr' can be used with a simple object and with many containers (stl, boost, Qt and 'qx::QxCollection' containers)
- '
qx::dao::ptr' keeps original values from database and provides a 'isDirty()' method to retrieve all properties changed
- '
qx::dao::update_optimized' must be used with 'qx::dao::ptr' to save into database only properties changed
Changes in version 1.1.3
- This version works fine with
MinGW on Windows
Changes in version 1.1.2
- License LGPL
- Fixed compilation problems on Linux and boost > 1.38
- Fixed SQL query with MySql database
- Disabled assert when
qx::dao functions return an error
Changes in version 1.1.1
- This version supports Visual Studio 2010
Changes in version 1.1.0