QxOrm - C++ ORM (对象关系映射) 库
QxOrm C++ 库:持久化 (基于 QtSql Qt 库) - 序列化 (基于 boost::serialization 库) - 反射 (内省)
![]() |
![]() | 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>
)
快速示例
快速示例步骤
- drug.h 文件:Drug 类定义,包含 3 个属性:id、name 和description
- drug.cpp 文件:'设置函数'实现:void qx::register_class()
- main.cpp 文件:QxOrm 库的基本功能,使用drug 类
- 执行程序并跟踪调试输出
- 创建了./export_drugs.xml 文件
#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_
#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'
}}
#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 文件
* ------------------------------------------------------------------------------
教程:qxBlog 项目
在本教程中,我们将通过创建一个 C++ 项目:qxBlog - C++ 中的博客管理,来介绍 QxOrm 库的许多功能。
qxBlog 教程步骤
- qxBlog 项目 - C++ 中的博客管理
- qxBlog 项目中的所有文件
- qxBlog.pro 文件
- export.h 文件
- precompiled.h 文件
- author.h 和author.cpp(一对多关系)
- comment.h 和comment.cpp(多对一关系)
- category.h 和category.cpp(多对多关系)
- blog.h 和blog.cpp(一对多、多对一和多对多关系)
- main.cpp 文件
- 与person类的“一对一”关系
- blog:1 篇blog由 1 位author撰写,可以包含多个comments,并且可以属于多个categories
- author:1 位author可以撰写多篇blogs
- comment:1 条comment属于 1 篇blog
- category:1 个category包含多个blogs
./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 机制,用于导入或导出函数、类等……)。
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.h 和author.cpp(一对多关系)
1 位author可以撰写多篇blogs:我们将学习如何使用一对多关系。
数据库中有 2 个表
在 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.h 和comment.cpp(多对一关系)
1 条comment属于 1 篇blog,而 1 篇blog可以包含多条comments:我们将学习如何使用多对一关系。
数据库中有 2 个表
与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.h 和category.cpp(多对多关系)
1 个category包含多个blogs,而 1 篇blog可以属于多个categories:我们将学习如何使用多对多关系。
这种关系需要一个新表在数据库中来保存每个关系的id列表。
因此,数据库中有 3 个表
与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.h 和blog.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");
}}
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;
}
重要提示:QxOrm 不想隐藏 SQL 查询(默认情况下,所有 SQL 查询都会显示)。
QxOrm 无法解决所有 SQL 和数据库问题,因此有时需要使用Qt
库的QtSql引擎来编写自己的 SQL 查询或存储过程。
QxOrm 也可用于“一对一”关系。
我们将类person(person.h和person.cpp文件)添加到我们的项目中:1 位person是 1 位author。
因此,person和author在数据库中共享相同的 id:这是一种一对一关系。
数据库中有 2 个表
注意:我们在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()在获取关系时被调用。
- 修复编译期间的发布模式检测:应能提高某些环境下的性能。
- 为QSqlError、qx::QxSqlQuery、qx::QxInvalidValue和qx::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_query
、update_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> 可与简单对象和多种容器一起使用(stl
、boost
、Qt
和 '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 版本更改
- 首次发布