65.9K
CodeProject 正在变化。 阅读更多。
Home

QxOrm - C++ ORM (对象关系映射) 库

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.90/5 (60投票s)

2010年10月23日

GPL3

26分钟阅读

viewsIcon

146979

downloadIcon

321

QxOrm C++ 库:持久化 (基于 QtSql Qt 库) - 序列化 (基于 boost::serialization 库) - 反射 (内省)

QxOrm
Qt Ambassador QxOrm 库已被接受加入 Qt大使计划
QxOrm 库在 Qt 官方网站上的页面

引言

QxOrm 是一个 C++ 库,旨在为 C++ 用户提供对象关系映射 (ORM) 功能。
通过一个简单的按类进行 C++ 设置函数(类似于Hibernate 的 XML 映射文件),您将可以使用以下功能:

  • 持久化:与多种数据库通信(支持一对一一对多多对一多对多关系)
  • 序列化:二进制和 XML 格式
  • 反射:访问类定义,检索属性和调用类方法

QxOrm 旨在简化 C++ 开发并提供大量功能。以下是 QxOrm 的优点列表:

  • 非侵入性C++ 设置函数不会修改类定义,QxOrm 可用于现有项目
  • 无代码生成
  • 无 XML 映射文件
  • 类无需继承自“超级对象”
  • 模板元编程:无宏 hack
  • 适用于 Windows 上的Visual C++ 2008 或 2010,Linux 上的GCC 4.4.1 和 Windows 上的MinGW(其他平台如 Mac、手机等将很快测试)
  • 只需在预编译头中包含一个文件<QxOrm.h>(需要预编译头文件以减少编译时间)

在安装和编译QxOrm之前,您需要以下库:boost(1.38 版本及以上)和Qt(4.5.0 版本及以上)。

注意:您可以使用 QxEntityEditor(QxOrm 库的图形编辑器)自动生成 Qt/C++ 项目源代码(更多详情请参见QxOrm 网站)!

Using the Code

QxOrm 库在 C++ 源代码中使用以下语法:

  • 所有类、函数、属性等都定义在命名空间 qx
  • QxOrm 库的所有宏都以QX_...开头
  • 所有abstract 类(或接口)都以Ix开头(例如,IxFactory 是创建对象实例的接口)
  • 其他类以Qx开头(例如,QxDataMember
  • 对象容器以X结尾(例如,QxDataMemberX QxDataMember的列表)
  • 与数据库交互的函数位于命名空间 qx::dao 下(例如,qx::dao::fetch_by_id()
  • 序列化函数位于命名空间 qx::serialization 下(例如,qx::serialization::xml::to_file()
  • 反射引擎可以使用qx::QxClassX(例如,使用qx::QxClassX::invoke() 调用类方法)
  • 所有 trait 类都位于命名空间 qx::trait 下(例如,qx::trait::is_smart_ptr<T>

快速示例

快速示例步骤

  1. drug.h 文件:Drug 类定义,包含 3 个属性:idnamedescription
  2. drug.cpp 文件:'设置函数'实现:void qx::register_class()
  3. main.cpp 文件:QxOrm 库的基本功能,使用drug
  4. 执行程序并跟踪调试输出
  5. 创建了./export_drugs.xml 文件

* ------------------------------------------------------------------------------------------
* 1- drug.h 文件:drug 类定义,包含 3 个属性:idnamedescription
* ------------------------------------------------------------------------------------------

#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)

/* This macro is necessary to register 'drug' class in QxOrm context */
/* param 1 : the current class to register => 'drug' */
/* param 2 : the base class, if no base class, use the qx trait => 
/* 'qx::trait::no_base_class_defined' */
/* param 3 : the class version used by serialization to provide 'ascendant compatibility' */

#endif // _CLASS_DRUG_H_

* ------------------------------------------------------------------------------------------
* 2- drug.cpp 文件:'设置函数'实现:void qx::register_class()
* ------------------------------------------------------------------------------------------

#include "precompiled.h"   // Precompiled-header with '#include <QxOrm.h>' 
                           // and '#include "export.h"'
#include "drug.h"          // Class definition 'drug'
#include <QxMemLeak.h>     // Automatic memory leak detection

QX_REGISTER_CPP_MY_TEST_EXE(drug)   // This macro is necessary to register 
                                    // 'drug' class in QxOrm context

namespace qx {
template <> void register_class(QxClass<drug> & t)
{
  t.id(& drug::id, "id");               // Register 'drug::id' <=> primary key 
                                        // in your database
  t.data(& drug::name, "name", 1);      // Register 'drug::name' property with 
                                        // key 'name' and version '1'
  t.data(& drug::description, "desc");  // Register 'drug::description' property 
                                        // with key 'desc'
}}

* ------------------------------------------------------------------------------------------
* 3- main.cpp 文件:QxOrm 库的基本功能,使用drug
* ------------------------------------------------------------------------------------------

#include "precompiled.h"
#include "drug.h"
#include <QxMemLeak.h>

int main(int argc, char * argv[])
{
   QApplication app(argc, argv); // Qt application

   // Create 3 new drugs
   // It is possible to use 'boost' and 'Qt' smart pointer : 
   // 'boost::shared_ptr', 'QSharedPointer', etc...
   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";

   // Insert drugs into container
   // It is possible to use a lot of containers from 
   // 'std', 'boost', 'Qt' and 'qx::QxCollection<Key, Value>'
   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);

   // Init parameters to communicate with a database
   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("");

   // Create table 'drug' into database to store drugs
   QSqlError daoError = qx::dao::create_table<drug>();

   // Insert drugs from container to database
   // 'id' property of 'd1', 'd2' and 'd3' are auto-updated
   daoError = qx::dao::insert(lst_drug);

   // Modify and update the second drug into database
   d2->name = "name2 modified";
   d2->description = "desc2 modified";
   daoError = qx::dao::update(d2);

   // Delete the first drug from database
   daoError = qx::dao::delete_by_id(d1);

   // Count drugs into database
   long lDrugCount = qx::dao::count<drug>();

   // Fetch drug with id '3' into a new variable
   drug_ptr d_tmp; d_tmp.reset(new drug());
   d_tmp->id = 3;
   daoError = qx::dao::fetch_by_id(d_tmp);

   // Export drugs from container to a file under xml format (serialization)
   qx::serialization::xml::to_file(lst_drug, "./export_drugs.xml");

   // Import drugs from xml file into a new container
   type_lst_drug lst_drug_tmp;
   qx::serialization::xml::from_file(lst_drug_tmp, "./export_drugs.xml");

   // Clone a drug
   drug_ptr d_clone = qx::clone(* d1);

   // Create a new drug by class name (factory)
   boost::any d_any = qx::create("drug");

   // Insert drugs container into 'qx::cache'
   qx::cache::set("drugs", lst_drug);

   // Remove all elements from 'qx::cache'
   qx::cache::clear();

   // Create a dummy memory leak
   drug * pDummy = new drug();

   return 0;
}

*-------------------------------------------------------------------------
* 4- 执行程序并跟踪调试输出
* -------------------------------------------------------------------------

[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 文件
* ------------------------------------------------------------------------------


quick_sample.export_drugs.xml

教程:qxBlog 项目

在本教程中,我们将通过创建一个 C++ 项目:qxBlog - C++ 中的博客管理,来介绍 QxOrm 库的许多功能。

qxBlog 教程步骤

  1. qxBlog 项目 - C++ 中的博客管理
  2. qxBlog 项目中的所有文件
  3. qxBlog.pro 文件
  4. export.h 文件
  5. precompiled.h 文件
  6. author.hauthor.cpp(一对多关系)
  7. comment.hcomment.cpp(多对一关系)
  8. category.hcategory.cpp(多对多关系)
  9. blog.hblog.cpp(一对多、多对一和多对多关系)
  10. main.cpp 文件
  11. person类的“一对一”关系

1- qxBlog 项目 - C++ 中的博客管理

  • blog:1 篇blog由 1 位author撰写,可以包含多个comments,并且可以属于多个categories
  • author:1 位author可以撰写多篇blogs
  • comment:1 条comment属于 1 篇blog
  • category:1 个category包含多个blogs

2- qxBlog 项目中的所有文件

./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

注意:教程源代码可在QxOrm目录的./test/qxBlog/文件夹中找到。
qxBlog.sqlite 文件是教程数据库,采用sqlite 格式。

3- qxBlog.pro 文件

此文件对于使用 Qt 库提供的qmake命令编译和构建项目至关重要。
qmake 工具是跨平台的,因此 qxBlog 项目可以在 Windows、Linux、Mac 等系统上编译……
qxBlog.pro 文件包含项目中所有文件(头文件 + 源文件)的列表以及所有依赖项(QxOrm.pri 文件包含 boost 和 Qt 库的所有依赖项)。
qxBlog.pro 包含一个重要的常量(_BUILDING_QX_BLOG),用于指示项目是否正在编译(参见export.h和 Windows 下的 DLL 机制,用于导入或导出函数、类等……)。

qxBlog.pro

4- export.h 文件

Windows DLL 需要此文件来管理类的“导出/导入”等。
QxOrm 使用相同的机制提供一些功能:因此,export.h 文件对于所有使用QxOrm库的项目都是必需的。

注意:Windows 下 DLL 机制的快速总结

  • 当 DLL 编译时,每个类都会被导出
  • 当另一个 DLL 编译时,第一个 DLL 的每个类都需要被导入才能使用
#ifndef _QX_BLOG_EXPORT_H_
#define _QX_BLOG_EXPORT_H_

#ifdef _BUILDING_QX_BLOG
#define QX_BLOG_DLL_EXPORT QX_DLL_EXPORT_HELPER
#else // _BUILDING_QX_BLOG
#define QX_BLOG_DLL_EXPORT QX_DLL_IMPORT_HELPER
#endif // _BUILDING_QX_BLOG

#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 // _BUILDING_QX_BLOG
#define QX_REGISTER_HPP_QX_BLOG QX_REGISTER_HPP_IMPORT_DLL
#define QX_REGISTER_CPP_QX_BLOG QX_REGISTER_CPP_IMPORT_DLL
#endif // _BUILDING_QX_BLOG

#endif // _QX_BLOG_EXPORT_H_

5- precompiled.h 文件

预编译头文件可减少 C++ 项目的编译时间。
QxOrm 使用元编程概念来提供大量功能。
元编程在编译时间上成本较高,因此使用precompiled.h文件可以大大加快项目的编译速度。

最后但同样重要的是,另一个优点是QxOrm.h文件包含了库boost Qt的基本功能。
因此,不再需要编写#include <QtCore/QString.h>来使用Qt QString 类。
同样,也不再需要编写#include <boost/shared_ptr.hpp>来使用boost 库的智能指针。

#ifndef _QX_BLOG_PRECOMPILED_HEADER_H_
#define _QX_BLOG_PRECOMPILED_HEADER_H_

#include <QxOrm.h>
#include "export.h"

#endif // _QX_BLOG_PRECOMPILED_HEADER_H_

6- author.hauthor.cpp(一对多关系)

1 位author可以撰写多篇blogs:我们将学习如何使用一对多关系。
数据库中有 2 个表

qxBlog.table.author

在 C++ 源代码中,author类的属性对应于数据库中author表的列。
因此,C++ 源代码中的 1 个author类实例对应于数据库中author表中的 1 行。
这种机制提供了易于开发和维护的 C++ 源代码。

我们在author类中添加了 1 个方法:int age(),用于根据数据库返回的数据检索年龄。
我们还定义了 2 个typedef:指向author对象的智能指针(使用 boost 库),以及author列表(使用 QxOrm 库的qx::QxCollection)。
author类需要一个QString类型的 id(默认情况下,QxOrm提供long类型的 id):我们使用宏QX_REGISTER_PRIMARY_KEY(author, QString)来特化模板。

#ifndef _QX_BLOG_AUTHOR_H_
#define _QX_BLOG_AUTHOR_H_

class blog;

class QX_BLOG_DLL_EXPORT author
{
public:
// -- typedef
   typedef boost::shared_ptr<blog> blog_ptr;
   typedef std::vector<blog_ptr> list_blog;
// -- enum
   enum enum_sex { male, female, unknown };
// -- properties
   QString     m_id;
   QString     m_name;
   QDate       m_birthdate;
   enum_sex    m_sex;
   list_blog   m_blogX;
// -- constructor, virtual destructor
   author() : m_id("0"), m_sex(unknown) { ; }
   virtual ~author() { ; }
// -- methods
   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 // _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_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.hcomment.cpp(多对一关系)

1 条comment属于 1 篇blog,而 1 篇blog可以包含多条comments:我们将学习如何使用多对一关系。
数据库中有 2 个表

qxBlog.table.comment

author类一样,我们定义了 2 个typedefs:指向comment对象的智能指针(使用boost 库),以及comments列表(使用Qt 库)。

#ifndef _QX_BLOG_COMMENT_H_
#define _QX_BLOG_COMMENT_H_

class blog;

class QX_BLOG_DLL_EXPORT comment
{
public:
// -- typedef
   typedef boost::shared_ptr<blog> blog_ptr;
// -- properties
   long        m_id;
   QString     m_text;
   QDateTime   m_dt_create;
   blog_ptr    m_blog;
// -- constructor, virtual destructor
   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 // _QX_BLOG_COMMENT_H_
#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.hcategory.cpp(多对多关系)

1 个category包含多个blogs,而 1 篇blog可以属于多个categories:我们将学习如何使用多对多关系。
这种关系需要一个新表在数据库中来保存每个关系的id列表。
因此,数据库中有 3 个表

qxBlog.table.category

author类和comment类一样,我们定义了 2 个typedefs:指向category对象的智能指针(使用Qt 库),以及categories列表(使用QxOrm 库)。

#ifndef _QX_BLOG_CATEGORY_H_
#define _QX_BLOG_CATEGORY_H_

class blog;

class QX_BLOG_DLL_EXPORT category
{
public:
// -- typedef
   typedef boost::shared_ptr<blog> blog_ptr;
   typedef qx::QxCollection<long, blog_ptr> list_blog;
// -- properties
   long        m_id;
   QString     m_name;
   QString     m_desc;
   list_blog   m_blogX;
// -- constructor, virtual destructor
   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 // _QX_BLOG_CATEGORY_H_
#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.hblog.cpp(一对多、多对一和多对多关系)

1 篇blog由 1 位author撰写,可以包含多个comments,并且可以属于多个categories
因此,这个类有 3 种关系:一对多、多对一和多对多
与其他类一样,我们定义了 2 个typedefs:指向blog对象的智能指针(使用 boost 库),以及blogs列表(使用stl 库)。

#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:
// -- properties
   long           m_id;
   QString        m_text;
   QDateTime      m_dt_creation;
   author_ptr     m_author;
   list_comment   m_commentX;
   list_category  m_categoryX;
// -- constructor, virtual destructor
   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 // _QX_BLOG_BLOG_H_
#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 文件

QxOrm 可以与多种数据库通信(在 Qt 网站上查看数据库列表)=> 持久化
QxOrm 还提供另外 2 项重要功能:

  • 序列化:二进制和 XML 格式
  • 反射:访问类定义,检索属性和调用类方法
#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[])
{
   // Qt application
   QApplication app(argc, argv);

   // Parameters to connect to database
   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("");

   // Ensure there is no element in database
   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>();

   // Create a list of 3 author
   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);

   // Insert list of 3 author into database
   daoError = qx::dao::insert(authorX);
   qAssert(qx::dao::count<author>() == 3);

   // Clone author n°2 : 'author_id_2'
   author_ptr author_clone = qx::clone(* author_2);
   qAssert(author_clone->m_id == "author_id_2");
   qAssert(author_clone->m_sex == author::female);

   // Create a query to fetch only female author : 'author_id_2' and 'author_id_3'
   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);

   // Dump list of female author (xml serialization)
   qx::dump(list_of_female_author);

   // Create 3 categories
   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";

   { // Create a scope to destroy temporary connection to database

   // Open a transaction to database
   QSqlDatabase db = qx::QxSqlDatabase::getDatabase();
   bool bCommit = db.transaction();

   // Insert 3 categories into database, use 'db' parameter for the 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);

   // Terminate transaction => commit or rollback if there is error
   if (bCommit) { db.commit(); }
   else { db.rollback(); }

   } // End of scope : 'db' is destroyed

   // Create a blog with the class name (factory)
   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;

   // Insert 'blog_1' into database with 'save()' method
   daoError = qx::dao::save(blog_1);

   // Modify 'blog_1' properties and save into database
   blog_1->m_text = "update blog_text_1";
   blog_1->m_author = author_2;
   daoError = qx::dao::save(blog_1);

   // Add 2 comments to '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);

   // Add 2 categories to 'blog_1' => must insert into extra-table 'category_blog'
   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);

   // Fetch blog into a new variable with all relation : 
   // 'author', 'comment' and 'category'
   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");

   // Dump 'blog_tmp' result from database (xml serialization)
   qx::dump(blog_tmp);

   // Call 'age()' method with class name and method name (reflection)
   qx_bool bInvokeOk = qx::QxClassX::invoke("author", "age", author_1);
   qAssert(bInvokeOk);

   return 0;
}

点击此处查看执行qxBlog程序后的调试输出跟踪……

重要提示QxOrm 不想隐藏 SQL 查询(默认情况下,所有 SQL 查询都会显示)。
QxOrm 无法解决所有 SQL 和数据库问题,因此有时需要使用Qt 库的QtSql引擎来编写自己的 SQL 查询或存储过程。

11- 与person类的“一对一”关系

QxOrm 也可用于“一对一”关系。
我们将类personperson.hperson.cpp文件)添加到我们的项目中:1 位person是 1 位author
因此,personauthor在数据库中共享相同的 id:这是一种一对一关系。
数据库中有 2 个表

qxBlog.table.person

注意:我们在person表中添加了mother_id列。因此,我们可以检索属于 1 位person的母亲(类型为person):这是一种在同一person表上的多对一关系。此外,如果 1 位person是母亲,我们可以检索孩子列表(类型为person):这是一种在同一person表上的一对多关系。

历史

1.4.6 版本更改

  • 新增 QxHttpServer 模块:C++/Qt 独立多线程 HTTP 1.1 Web 服务器(支持 SSL/TLS、持久连接、Cookie、会话、分块响应、URL 调度器/路由,除 QtNetwork 外无其他依赖):https://www.qxorm.com/qxorm_en/manual.html#manual_96
  • 新增 QxRestApi 模块:提供 REST API,以 JSON 格式发送来自外部应用程序(Web 服务)、网站(例如用 Angular 编写)、QML 或脚本语言(如 Python)的请求:https://www.qxorm.com/qxorm_en/manual.html#manual_97
  • 通过 QxHttpServer 和 QxRestApi 模块,QxOrm 库现在可用于创建 Web 应用程序,特别是单页应用程序 (SPA),可与 AngularJS、React、Meteor.js 等流行的 JavaScript 框架一起使用。
  • 新增项目示例“qxBlogRestApi”:QML 应用程序,包含 REST 请求列表,展示如何从 JavaScript 向 QxRestApi 模块发送 JSON 查询 + HTTP Web 服务器应用程序,展示如何使用 QxHttpServer 模块创建 Web 应用程序。
  • QxRestApi 模块支持:所有 CRUD 操作、复杂查询、多级关系、自定义 JSON 输出格式、动态调用 QxOrm 上下文中注册的原生 C++ 函数、实例验证、调用自定义数据库查询。
  • 改进 JSON 序列化引擎:可定义自定义过滤器以不导出所有属性(https://www.qxorm.com/qxorm_en/manual.html#manual_606)。
  • 可通过语法 <my_table_alias> 定义自定义 SQL 表别名以处理带关系(https://www.qxorm.com/qxorm_en/manual.html#manual_3850)。
  • 改进 Oracle 数据库的 SQL 生成器:使用 RETURNING INTO 语法管理最后一个插入的 ID(感谢 Romain Macureau 和 Abdennour Boutrig)。
  • 修复存储过程和输出参数的问题。
  • 新增可用函数:qx::dao::count_with_relation<t>()
  • 修复多线程环境下的 JSON 序列化问题。
  • 更改 JSON QDateTime 和 QTime 序列化格式:使用 Qt::ISODateWithMs 而非 Qt::ISODate(Qt 5.8 或以上)。
  • 改进 QxService 模块:支持 SSL/TLS 安全连接 + Keep-alive 连接。
  • 从 QxOrm 包中移除 *.suo 文件(MSVC++ 临时项目文件)。

1.4.5 版本更改

  • 支持 MongoDB 数据库:QxOrm 库现已成为 C++/Qt 对象文档映射 ODM 库!
  • 有关 MongoDB 集成的更多详细信息,请参阅 QxOrm 手册(https://www.qxorm.com/qxorm_en/manual.html#manual_95)和 ./test/qxBlogMongoDB/ 目录中提供的新示例项目。
  • QxOrm 库现已在 GitHub(官方仓库)上线:https://github.com/QxOrm/QxOrm
  • 修复 qx::IxSqlQueryBuilder 类在 QxOrm 库用于多线程环境时出现的问题。
  • 支持最新版本的 boost(1.66)。
  • 将 boost 可移植二进制序列化类更新至 5.1 版本(来自 https://archive.codeplex.com/?p=epa)。
  • 修复 Oracle 数据库生成 SQL 查询时出现的问题(不支持 AS 关键字作为表别名)。
  • 改进 qx::QxClassX::registerAllClasses() 函数:可初始化所有关系(适用于与内省引擎配合使用)。
  • 改进 qx::IxPersistable 接口:提供新的 toJson() / fromJson() 方法。
  • 改进文档/网站:将 http://www.qxorm.com 替换为 HTTPS://www.qxorm.com。
  • 修复使用软删除时,在 JOIN 部分而不是 WHERE 部分放置 SQL 条件来获取关系的问题。
  • 修复 Oracle 数据库的 SQL 生成器:使用新的 limit/pagination 语法(Oracle 版本 > 12.1)。
  • 改进 SQL 生成器接口:添加 'onBeforeSqlPrepare()' 方法,用于在自定义类中修改/记录 SQL 查询。
  • 在 qx::QxSqlDatabase 类中添加一个选项,用于在记录 SQL 查询前格式化 SQL 查询(美化打印)(可通过创建 qx::dao::detail::IxSqlGenerator 子类来自定义)。
  • 修复 boost/std::optional(用于处理 NULL 数据库值)与某些数据库之间的问题:如果 optional 为空,则基于 QVariant::Type 创建一个 NULL QVariant。
  • 在 qx::QxSqlDatabase 类中添加一个选项,用于在 SQL 查询中插入方括号(或其他分隔符)作为表名和/或列名(以支持特定的数据库关键字)。
  • 改进内省引擎:在 qx::IxDataMember 接口中添加 getType() 方法,以动态获取属性的 C++ 类型。
  • 改进 qx::QxSqlDatabase 单例设置类,以便更容易地使用多个数据库:现在有 3 级设置:全局 >> 每个线程 >> 每个数据库(请参见所有 setXXXX() 方法中的 'bJustForCurrentThread' 和 'pJustForThisDatabase' 可选参数)。
  • 修复 MinGW 编译器在 Windows 上的 QxOrm.pri:导出共享库中的某些符号(例如某些 Qt 信号)时可能出现问题。
  • 在 qx::QxSqlDatabase 单例类中添加一个选项,用于仅显示慢速 SQL 查询(请参见 setTraceSqlOnlySlowQueriesDatabase() 和 setTraceSqlOnlySlowQueriesTotal() 方法)。

1.4.4 版本更改

QxOrm 库不再依赖 boost 框架(已完全移除 boost 依赖,替换为一些 C++11 特性)。因此,QxOrm 库现在是一个纯 Qt 库,默认情况下仅依赖 QtCore 和 QtSql。为向后兼容,QxOrm 库仍支持一些 boost 类(boost 智能指针、无序容器、boost::optional 等):您需要定义 _QX_ENABLE_BOOST 编译选项来启用这些功能。

主要优点是:

  • QxOrm 变得更轻量级
  • 安装更容易(因为您不再需要处理 boost)
  • 减少编译时间
  • 减小输出二进制文件大小

还要感谢 Jimmy Taker 对 QxModelView 模块的几项改进和新功能!

  • QxOrm 库现在需要 C++11 编译器(请注意,QxOrm 不需要完全符合标准的 C++11 编译器:例如,QxOrm 可以使用 MSVC 2012、GCC 4.5 或 Clang 3.2 构建和使用)。
  • 为某些 QxOrm 类实现 PIMPL idiom,以减少编译时间和输出二进制文件大小。
  • 新增名为 qx::any 的类,以替换 boost::any(Kevlin Henney 编写的 boost::any 的基本实现)。
  • qx_shared_ptr 别名不再存在:它已被 std::shared_ptr 处处替换。
  • QxModelView 模块:所有基于 qx::IxModel 类的模型现在都可以排序(在所有列上),请注意,您也可以使用 QSortFilterProxyModel Qt 类来排序您的模型。
  • QxModelView 模块 - qx::QxModel:修复 setData() 在 e_auto_update_on_field_change 选项下,当保存数据到数据库时发生错误,现在如果发生错误,之前的会恢复。
  • QxModelView 模块 - qx::IxModel:使用默认角色(Qt::EditRole)的 setHeaderData() 会在标头视图中更改标头(角色 Qt::DisplayRole)。
  • QxModelView 模块 - qx::IxModel:如果在 QxOrm 上下文中注册了描述,则它将在每个属性的标头中显示。
  • QxModelView 模块:新增功能,可在表末尾自动添加一个空行,以便快速插入新项(setShowEmptyLine() 方法)。
  • QxModelView 模块:可定义一个中间基类在 qx::IxModel 和 qx::QxModel 之间,以提供您自己的模型功能。例如,假设您在一个名为 IxModelDragDrop 的类中开发拖放功能,您现在可以像这样创建一个 QxOrm 模型(参见第二个模板参数):qx::IxModel * pModel = new qx::QxModel<MyPersistantClass, IxModelDragDrop>()。
  • QxOrm.pro:修复 Windows 上的 DESTDIR 参数。
  • QxOrm.pri 和 QxOrm.cmake:添加一个部分以启用 QT_USE_QSTRINGBUILDER 来优化 QString 操作。
  • QxOrm 库现在使用 MSVC 2015 编译器进行测试(支持所有 MSVC 版本从 2012 年起)。
  • 修复 QxSqlError.h 文件中对临时对象调用 qPrintable() 的错误。
  • 在执行 SQL 查询后提供更多日志详细信息:数据库执行查询时间 + C++ 实例获取时间。
  • 支持 std::optional<T>(如果您的编译器支持 C++17 特性)来处理 NULL 数据库值:新增名为 <QxExtras/QxStdOptional.h> 的头文件,应在 <QxOrm.h> 头文件之后包含(最好在预编译头中)。

1.4.3 版本更改

  • 支持 CMake:添加了新的 CMakeLists.txt 文件,用于使用 CMake 构建 QxOrm 库;
  • 当 qx::dao 函数返回数据库错误时,改进 SQL 错误消息;
  • 单例类 qx::QxSqlDatabase 中的新参数用于记录 SQL 绑定值(setTraceSqlBoundValues):默认情况下,在发生错误时记录绑定值;
  • 选择不获取的列的新语法:-{ col_1, col_2, 等… };
  • 新函数 qx::dao::call_query_without_prepare(),用于执行特定的 SQL 查询而无需预处理语句;
  • 改进 QxModelView 模块:所有 QxOrm 模型(基于 qx::IxModel 接口)都可以序列化为 JSON 格式(包括所有关系级别):这是另一种处理关系和 QML 的方式(借助 JSON.parse() 和 JSON.stringify() JavaScript 函数),无需使用嵌套模型概念(因此无需使用 QxEntityEditor 模型/视图生成的类);
  • 改进 qxBlogModelView 示例项目和 QxOrm 手册,以展示如何在 QML 中访问关系数据(嵌套模型或 JSON);
  • 修复 qx::QxSqlRelation 类中的内存泄漏;
  • 减小输出二进制文件大小(约 20%)和编译时间(约 20%)来构建基于 QxOrm 库的持久化类;
  • 支持 Unity Build 概念,以减少构建 QxOrm 库和 QxEntityEditor 应用程序生成的 C++ 持久化类的时间:有关更多详细信息,请参见 QxOrm.pri 或 QxOrm.cmake 配置文件中的 _QX_UNITY_BUILD 编译选项。
  • 改进 QxConvert 模块:可以将包含 QVariantMap、QVariantHash 或 QVariantList 类型的复杂 QVariant 属性存储到数据库(JSON 格式)。
  • 修复了某些数据库中,外键同时也是主键一部分的问题;
  • 修复了反序列化过程中,同一原始指针被多个 QSharedPointer 共享时,QSharedPointer 和 boost::serialization 的问题。

1.4.2 版本更改

  • 支持 JSON 序列化:在 QxOrm 上下文中注册的每个 C++ 类都可以序列化/反序列化为 JSON 格式(JSON 功能需要 Qt5);
  • 有关 JSON 序列化的更多详细信息,请在此处阅读 QxOrm 手册:http://www.qxorm.com/qxorm_en/manual.html#manual_606;
  • 通过 JSON 序列化和 QxService 模块:现在可以创建 REST Web 服务,将数据发送到 JavaScript 引擎(例如网页);
  • 修复了使用最新(且更严格)编译器以及最新版本的 boost 和 Qt 时的一些编译错误;
  • 修复了在大型数据库模式中,具有复杂、深度和循环关系的初始化断言;
  • 改进 QDataStream 序列化:现在应该更快,并修复了循环实例依赖项的问题;
  • 修复了获取 1-n 和 n-n 关系时,根是堆栈对象容器的问题(仅适用于指针或智能指针,例如:QList<blog> 而不是 QList<std::shared_ptr<blog>>);
  • 改进 qx::dump() 函数:可将 C++ 实例状态显示为 XML 或 JSON 格式。

1.4.1 版本更改

!!!关于此版本的重要提示!!!:强烈建议阅读此版本的新 QxOrm.pri 配置文件(与以前的版本相比,编译选项已更改)。现在,默认情况下,QxOrm 库是一个更轻量级的库:QxOrm 仅依赖 QtCore 和 QtSql(boost 序列化现在是可选的,默认不要求)。默认情况下,序列化引擎基于 Qt QDataStream 类(但您仍然可以通过在 QxOrm.pri 配置文件中定义 _QX_ENABLE_BOOST_SERIALIZATION 编译选项来启用 boost 序列化)。因此,现在,使用默认选项:

  • QxOrm 1.4.1 更容易安装,因为您无需处理 boost 序列化的额外依赖项;
  • QxOrm 1.4.1 共享库比 1.3.2 版本小 3 倍;
  • 依赖 QxOrm 库生成的二进制文件小 25%;
  • 如果您在当前项目中使用基于 QxOrm 库的序列化函数,则可以通过定义或不定义 _QX_ENABLE_BOOST_SERIALIZATION 编译选项,而无需更改源代码中的任何行。

以下是 1.4.1 版本的所有其他更改:

  • 改进关系引擎:可以通过语法 my_relation { col_1, col_2, 等… } 来选择要获取的列;
  • 改进 QxTraits 模块,以减少编译时间和生成更小的二进制文件;
  • 改进 QxOrm 网站,增加了搜索功能,并用更易于组织的手册(用户指南)替换了旧的 FAQ;
  • 新的编译选项 _QX_ENABLE_BOOST_SERIALIZATION,用于启用 boost 序列化依赖项(有关详细信息,请阅读 QxOrm.pri 配置文件);
  • 新的编译选项 _QX_ENABLE_QT_NETWORK,用于启用 QxService 模块(通过网络传输持久化层):有关详细信息,请阅读 QxOrm.pri 配置文件;
  • 新的编译选项 _QX_NO_RTTI,用于在不使用 C++ RTTI 类型信息的情况下构建 QxOrm 库;
  • 支持 QDataStream Qt 序列化引擎(当未定义 _QX_ENABLE_BOOST_SERIALIZATION 编译选项时默认使用);
  • 改进 qx_query 类(SQL 查询):新增方法(名为 customOperator()),允许定义自定义运算符(例如,用于 PostgreSQL ltree 类型);
  • 修复了由于“静态初始化顺序陷阱”创建单例而导致的程序启动问题(在某些编译器共享库链接过程中存在此问题);
  • 新的命名空间 qx::dao::throwable:与 qx::dao 命名空间的功能相同,但当发生 SQL 错误时,它们会抛出 qx::dao::sql_error 异常(而不是返回 QSqlError 实例);
  • 添加 qAssertMsg() 宏,在抛出断言时提供更明确的错误消息;
  • 将所有 *.inl 文件(模板实现)包含在 QxOrm.pro 项目文件中:QtCreator 现在可以在其项目树状视图中索引这些 *.inl 文件;
  • 重命名 QxStringCvt 为 QxConvert:因此,如果您将自定义类型持久化到数据库,则需要将 QxStringCvt_FromVariant、QxStringCvt_ToVariant 重命名为 QxConvert_FromVariant、QxConvert_ToVariant。

1.3.2 版本更改

  • 支持 C++11 类型(需要在 QxOrm.pri 配置文件中设置编译选项以启用这些功能)
  • 使用 _QX_CPP_11_SMART_PTR 编译选项:std::unique_ptr, std::shared_ptr, std::weak_ptr
  • 使用 _QX_CPP_11_CONTAINER 编译选项:std::unordered_map, std::unordered_set, std::unordered_multimap, std::unordered_multiset
  • 使用 _QX_CPP_11_TUPLE 编译选项:std::tuple

1.3.1 版本更改

  • QxModelView 模块中新增类 qx::QxModelService,用于将 Qt 模型连接到服务以执行客户端-服务器请求(可与 QML 和 QtWidgets 视图一起使用)。
  • 为 qx::IxModel 类添加了一些有用的方法,并修复了 QxModelView 模块的几个问题。
  • 支持最新版本的 MinGW,并修复了预编译头大型文件 bug:新增编译选项 _QX_NO_PRECOMPILED_HEADER(在 QxOrm.pri 文件中启用)。
  • 修复了在 Windows 上加载多个共享库时,与 QxService 模块中注册的服务相关的问题。
  • 修复了 QxService 模块用于通过网络发送请求的 qx::QxSqlQuery 序列化过程。
  • 修复了 qx::QxCollection 类在最后位置插入项目时出现的问题。

1.2.9 版本更改

  • 改进 QxModelView 模块中的嵌套模型,以便在 QML 中使用多个关系级别。

1.2.8 版本更改

  • QxModelView 模块中的新函数 qx::model_view::create_nested_model,由 QxEntityEditor 使用,以管理复杂数据结构,从而在 QML 视图和 Qt 模型/视图架构中处理关系。
  • Qx.pri 文件中新增一节,提供减少输出二进制文件大小的技巧。
  • 修复了 PostgreSQL 中的触发器调用,以便在触发器函数中获得插入的 ID。

1.2.7 版本更改

  • 新模块 QxModelView:现在,所有在 QxOrm 上下文中注册的类都可以与 Qt 模型/视图架构一起使用(Qt 部件和/或 QML 视图)。
  • qx::IxModel 接口提供了一种简单的方式,可以在 QML 中使用 QxOrm 库并与数据库进行交互。
  • 有关新模块 QxModelView 的更多详细信息,请参阅 FAQ:“如何使用 QxModelView 模块与 Qt 模型/视图架构(Qt 部件和/或 QML 视图)进行交互?”
  • 新函数 qx::dao::save_with_relation_recursive(),可用于例如保存整个树状结构。
  • 移除对 Qt 中的 STL 兼容性函数(QT_NO_STL)的依赖,这些函数可能不可用(感谢 KDE Plasma Media Center 团队提供的补丁)。
  • 支持定义在 schema 中的数据库表(使用 qx::IxDataMember::setName() 函数)。

1.2.6 版本更改

  • 第一个完全兼容 QxEntityEditor 应用程序的版本:QxOrm 库的图形编辑器!
  • 有关 QxEntityEditor 的更多详细信息,请访问 QxOrm 网站:http://www.qxorm.com/
  • 得益于 Qt 5.2 的最新发布,QxOrm 库现在可以在 Android 和 iOS 上使用。
  • 改进关系和触发器引擎。
  • 触发器onBeforeFetch()onAfterFetch()在获取关系时被调用。
  • 修复编译期间的发布模式检测:应能提高某些环境下的性能。
  • QSqlErrorqx::QxSqlQueryqx::QxInvalidValueqx::QxInvalidValueX类添加序列化。

1.2.5 版本更改

  • 新许可证:有关更多详细信息,请访问 QxOrm 网站的下载页面。
  • 支持 Qt5。
  • 新增支持的编译器:Clang(在 Mac OS X 上测试)。
  • 现在每个 QxOrm 版本都将在 32 位和 64 位模式下进行测试。
  • 改进 QxOrm 内省引擎:可注册静态类方法。
  • 改进 QxService 模块:现在可以轻松地在服务器端添加身份验证过程。
  • 新类 qx::exception,用于获取服务方法抛出异常时的错误代码 + 错误描述。
  • QxOrm.pri 配置文件中新增了可用设置(无需更改 QxConfig.h 文件)。
  • 可实现特定数据库 SQL 函数,方法是重写 qx_query 类。
  • 修复了获取多层关系和 NULL 指针时出现的问题。
  • 修复了 MS SQL Server 数据库和使用自动递增 id 的更新查询的 bug。

1.2.4 版本更改

  • 新关系引擎,可轻松地通过单次查询获取多层关系。
  • 有关此新引擎的更多详细信息,请参阅 FAQ:“如何使用关系引擎从多个表中获取数据?”
  • 添加 2 个函数:qx::dao::execute_query 和 qx::dao::call_query,用于调用存储过程或自定义 SQL 查询。
  • 有关此新功能更详细信息,请参阅 FAQ:“如何执行存储过程或自定义 SQL 查询?”
  • 添加了对 boost::optional 类型的支持,以处理 NULL 数据库值,而无需使用 QVariant 类型。
  • 新类:qx::QxDaoAsync,以便更容易地以异步方式(多线程)执行查询。
  • 有关此新类的更详细信息,请参阅 FAQ:“如何使用 qx::QxDaoAsync 类以异步方式(多线程)执行查询?”

1.2.3 版本更改

  • 新接口 'qx::IxPersistable'(抽象类),用于简化使用 QxOrm 库的多态。
  • 有关此新接口的更多详细信息,请参阅 FAQ:“如何使用qx::IxPersistable 接口?
  • 在 'qx::IxCollection' 接口中新增方法,用于迭代每个项目,而无需知道其类型。
  • 在 'QxOrm.pri' 文件中新增选项,用于静态构建 QxOrm 库(参见 '_QX_STATIC_BUILD' 选项)。
  • 新触发器:'qx::dao::on_before_fetch' 和 'qx::dao::on_after_fetch'(有关更多详细信息,请参阅 FAQ:“如何使用 QxOrm 定义触发器?”)。
  • 将 'std::type_info' 类信息添加到内省引擎。
  • 修复了一些小 bug('qx::dao::sql_error' 异常消息、SQL 查询列别名、互斥锁等)。

1.2.2 版本更改

  • 新模块,用于提供验证引擎:QxValidator 模块。
  • 有关QxValidator 模块的更多详细信息,请参阅QxOrm 库的 FAQ:“如何使用QxValidator 模块自动验证实例?”
  • 修复了 PostgreSQL 使用 'RETURNING' 关键字时的最后插入 ID:获取插入的 ID 而不是 OID。
  • 改进 SQL 生成器,为所有数据库提供正确的 SQL 类型。
  • 添加了对特殊数据库关键字的支持,使用 '[', ']' 和 '"' 字符。

1.2.1 版本更改

  • 改进 'qx::QxSqlQuery' 类:新的引擎,无需编写 SQL 即可构建查询,有关更多详细信息,请参阅 FAQ“如何使用 qx::QxSqlQuery 类在不编写 SQL 的情况下构建查询?”
  • 改进 'qx::QxSession' 类:提供持久化方法(CRUD),无需使用 'qx::dao::xxx' 函数,有关更多详细信息,请参阅 FAQ“如何使用会话(qx::QxSession 类)自动管理数据库事务(使用 C++ RAII)?”
  • 实现“存储库”模式,为持久化方法(CRUD)提供通用接口,包含 3 个新类:'qx::IxRepository'、'qx::QxRepository<t>' 和 'qx::QxRepositoryX'。
  • 可以将QVariant 的 'UserType' 与QxOrm 库的序列化引擎进行序列化。
  • 改进线程安全的 'qx::cache':在缓存中添加插入日期/时间,以验证元素是否需要更新(有关更多详细信息,请参阅 FAQ“如何使用QxOrm 库的缓存(qx::cache 命名空间中的函数)?”)。
  • FAQ 已在QxOrm 网站上更新,现在有 28 个问答。

1.1.9 版本更改

  • 可以自动注册 Qt 元属性(使用Q_PROPERTY宏)到 QxOrm 上下文,而无需为每个类编写映射函数(void qx::register_class<t>()</t><t>)。
  • 与 Qt 内省/moc 引擎的强集成:有关此新功能的更多详细信息,请参阅 FAQ“如何自动将 Qt 元属性注册到 QxOrm 上下文?”
  • 改进内省/反射引擎:请参阅 FAQ(如何使用 QxOrm 库的内省引擎(或反射引擎)?)以获取更多详细信息。
  • 可以向内省引擎添加元数据(使用属性包):有关更多详细信息,请参阅 'IxClass'、'IxDataMember' 和 'IxFunction' 类。
  • 添加函数 'qx::QxClassX::dumpSqlSchema()' 来解释如何基于 C++ 类创建自己的 SQL schema。
  • 新类 'qx::QxSimpleCrypt' 提供加密/解密功能(非常感谢 Andre Somers):因此,现在可以在不使用外部库的情况下将加密数据存储到数据库中。
  • QxService 模块:新增功能,可在网络传输数据之前进行加密/解密。

1.1.8 版本更改

  • QxOrm 库现在可以在 Mac 上使用(非常感谢 Dominique Billet):请参阅 'osx_build_all_debug.sh' 和 'osx_build_all_release.sh' 脚本来构建 QxOrm 库和 './test/' 目录中的所有示例。
  • 添加 'qx::QxSession' 类:定义一个会话来自动管理数据库事务(使用 C++ RAII),有关更多详细信息,请参阅 FAQ。
  • 添加 'qx::QxDateNeutral'、'qx::QxTimeNeutral' 和 'qx::QxDateTimeNeutral' 类:辅助类,用于将日期/时间值以中性格式存储到数据库中,从而实现跨数据库兼容性。

1.1.7 版本更改

  • 添加了软删除行为:有关此新功能的更多详细信息,请参阅 FAQ(如何定义软删除行为?)。
  • 在 'qx::dao' 命名空间中添加了用于通过 SQL 条件更新元素的函数:update_by_queryupdate_optimized_by_query 等。
  • 修复了当属性的类型为QVariant 时出现的 bug:现在可以向数据库插入NULL 值。

1.1.6 版本更改

  • QxOrm 库在线文档可用:http://www.qxorm.com/doxygen/index.html
  • 可以通过 'QxConfig.h' 文件中的编译选项禁用QtGui 依赖项:_QX_ENABLE_QT_GUI_DEPENDENCY
  • 可以通过 'QxConfig.h' 文件中的编译选项禁用QtNetwork 依赖项(因此也禁用QxService 模块):_QX_ENABLE_QT_NETWORK_DEPENDENCY
  • 提供了一个新宏,用于将abstract 类注册到QxOrm 上下文:QX_REGISTER_ABSTRACT_CLASS()

1.1.5 版本更改

  • 新功能可用:“QxService”模块,用于创建 C++ 应用程序服务器。
  • QxService”提供了一种简单而强大的方法来创建服务和传输数据。
  • 新增教程,解释“QxService”模块的工作原理。
  • 新增示例,位于 './test/qxClientServer' 目录。
  • 可以使用 'CONFIG += no_keywords' 标志在 '*.pro' 文件中构建QxOrm
  • 修复了 'qx::dao::create_table<>' 函数和“多对多”关系中的 bug。
  • QxOrm 现在应该可以与 GCC <= 4.2 正常构建。

1.1.4 版本更改

  • 为 'qx::dao::fetch_by_id'、'qx::dao::fetch_all'、'qx::dao::fetch_by_query' 和 'qx::dao::update' 函数新增参数,用于定义要获取/更新的属性列表(默认情况下,所有属性都将获取/更新)。
  • 支持多列主键(复合键):请参阅示例 './test/qxBlogCompositeKey/'。
  • 改进了继承策略:QxOrm 支持“具体表继承”策略(“具体表继承”成为默认策略)。
  • 新的智能指针 'qx::dao::ptr'<t>,基于 Qt 的 'QSharedPointer',提供 2 项新功能:“is dirty”(是否脏)和“update optimized”(优化更新)。
  • 'qx::dao::ptr'<t> 可与简单对象和多种容器一起使用(stlboostQt 和 'qx::QxCollection' 容器)。
  • 'qx::dao::ptr'<t> 保留数据库中的原始值,并提供 'isDirty()' 方法来检索所有已更改的属性。
  • 必须与 'qx::dao::ptr'<t> 一起使用 'qx::dao::update_optimized',才能仅将已更改的属性保存到数据库中。

1.1.3 版本更改

  • 此版本在 Windows 上的MinGW下工作正常。

1.1.2 版本更改

  • 许可证 LGPL。
  • 修复了 Linux 和 boost > 1.38 上的编译问题。
  • 修复了与 MySQL 数据库的 SQL 查询。
  • qx::dao 函数返回错误时禁用 assert。

1.1.1 版本更改

  • 此版本支持 Visual Studio 2010。

1.1.0 版本更改

  • 首次发布
© . All rights reserved.