概要
QxOrm 库是面向 C++/Qt 开发人员的对象关系映射 (ORM)数据库。
官网:QxOrm官网链接
进入官网Download页面即可下载源码以及说明文档等。
如图所示,目前最新版本为1.4.9。
示例整体结构和环境配置
如图所示,在案例中app为实际运行窗体项目程序,通过component子项目来统一管理引入QxOrm相关依赖
需要注意的是在component子项目中引入了QxOrm相关依赖后因为项目结构进行拆分,我这里在QxOrm.pro中配置了编译输出库文件指定到app窗体项目程序的lib文件夹下,方便管理debug、release不同模式的QxOrm相关库文件依赖。
在app窗体程序项目中添加相关配置文件:
export.h:
#ifndef EXPORT_H
#define EXPORT_H
#ifdef _BUILDING_QXORM // 判断是否正在构建 QxOrm 库
#define QX_DLL_EXPORT QX_DLL_EXPORT_HELPER // 如果正在构建,使用 QX_DLL_EXPORT_HELPER 宏作为导出宏
#else
#define QX_DLL_EXPORT QX_DLL_IMPORT_HELPER // 如果不是正在构建,使用 QX_DLL_IMPORT_HELPER 宏作为导入宏
#endif
#ifdef _BUILDING_QXORM // 判断是否正在构建 QxOrm 库,然后选择使用导出或导入宏
#define QX_REGISTER_HPP QX_REGISTER_HPP_EXPORT_DLL
#define QX_REGISTER_CPP QX_REGISTER_CPP_EXPORT_DLL
#else
#define QX_REGISTER_HPP QX_REGISTER_HPP_IMPORT_DLL
#define QX_REGISTER_CPP QX_REGISTER_CPP_IMPORT_DLL
#endif
#endif // EXPORT_H
在动态库调用中,使用宏定义有助于处理一些平台和编译器差异,以及提供更灵活和可移植的代码。
precompiled.h:
#ifndef PRECOMPILED_H
#define PRECOMPILED_H
#include <QxOrm.h>
#include "export.h"
#endif // PRECOMPILED_H
// 预编译头文件,此文件写好后几乎不会变动,可以减少后期的编译时间
precompiled.h为预编译头文件,预编译头文件的作用主要是为了提高编译效率。通过预编译头文件,编译器可以事先编译和预处理一些常用的头文件内容,然后将其保存到一个二进制文件中。在后续的编译过程中,可以直接使用这个预编译的头文件,从而避免重复编译相同的头文件内容,提高编译速度。
最后需要注意的是在窗体程序.pro中配置先前在export.h中编写的动态库调用宏定义能够通过宏定义_BUILDING_QXORM得知项目是否正在编译,这样可以在编译时根据项目是否处于构建状态来选择性地包含或排除某些代码。这在处理库的导出和导入、或者在不同的构建配置下进行条件编译时非常有用。
增删改查
在QxOrm上下文中注册一个类(映射)。
下面是一个示例,展示如何定义一个名为person的类,该类在 QxOrm 上下文中注册了 4 个属性:id、name、age :
person.h:
#ifndef PERSON_H
#define PERSON_H
#include "precompiled.h" // 引入预编译头文件
// 使用 QX_DLL_EXPORT 宏导出 Person 类,用于动态链接库的导出
class QX_DLL_EXPORT Person
{
public:
long id; // ID
QString name; // 姓名
int age; // 年龄
Person() : id(0) { ; } // 构造函数,初始化 id 为 0
virtual ~Person() { ; }
};
// 在 QxOrm 中注册 Person 类
QX_REGISTER_HPP(Person, qx::trait::no_base_class_defined, 0)
/* 这个宏对于在 QxOrm 上下文中注册 'person' 类是必要的 */
/* param 1 : 当前要注册的类 => 'person' */
/* param 2 : 基类,如果没有基类,则使用 qx Trait => 'qx::trait::no_base_class_define' */
/* param 3 : 序列化引擎用于提供“上升兼容性”的类版本 */
#endif // PERSON_H
person.cpp:
#include "precompiled.h" // 预编译头文件,包含了 '#include <QxOrm.h>' 和 '#include "export.h"'
#include "person.h" // 引入 Person 类的定义
#include <QxOrm_Impl.h> // 自动内存泄漏检测和 Boost 序列化导出宏
QX_REGISTER_CPP(Person) // 使用宏注册 Person 类,将其注册到 QxOrm 上下文中
namespace qx
{
// QxOrm 的类注册模板特化,用于定义 Person 类的属性
template <> void register_class<QxClass<Person>>(QxClass<Person> & t)
{
t.setName("t_person"); // 设置表名为 "t_person"
t.id(&Person::id, "id"); // 注册 id 属性
t.data(&Person::name, "name"); // 注册 name 属性
t.data(&Person::age, "age"); // 注册 age 属性
}
}
注意:类方法qx::QxClass::id()和qx::QxClass::data()返回类型为qx::IxDataMember的实例(这是注册数据成员的基类) )。通过此实例,可以自定义qx::IxDataMember类的默认行为,例如“注册瞬态数据成员”一章中的示例。
其他注意事项:还可以使用qx::QxClass::fct_0()、qx::QxClass::fct_1()在 QxOrm 上下文中注册函数和类方法(支持静态和非静态方法)等等…此功能是 QxOrm 库内省引擎的一部分。
编写CRUD测试方法:
mainwindow.h:
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QxOrm_Impl.h>
#include "precompiled.h"
#include "person.h"
QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = nullptr);
~MainWindow();
private:
Ui::MainWindow *ui;
void addSqlConnection(); // 添加数据库连接
void insertData(); // 插入数据
void deleteData(); // 删除数据
void updateData(); // 修改数据
void selectData(); // 查询数据
};
#endif // MAINWINDOW_H
在需要使用到QxOrm的地方引入自动内存泄漏检测和 Boost 序列化导出宏 #include <QxOrm_Impl.h> 和预编译宏 #include “precompiled.h” 以及 数据库映射类,这里是person。
mainwindow.cpp:
#include "mainwindow.h"
#include "ui_mainwindow.h"
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
addSqlConnection();
insertData();
deleteData();
updateData();
selectData();
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::addSqlConnection()
{
qx::QxSqlDatabase::getSingleton()->setDriverName("QSQLITE");
qx::QxSqlDatabase::getSingleton()->setDatabaseName("./database.db");
qx::QxSqlDatabase::getSingleton()->setHostName("localhost");
qx::QxSqlDatabase::getSingleton()->setUserName("root");
qx::QxSqlDatabase::getSingleton()->setPassword("");
QSqlError sqlError;
QSqlDatabase db = qx::QxSqlDatabase::getDatabase();
// 检查连接是否有效
if (db.isValid())
{
qDebug() << "数据库连接成功!";
sqlError = qx::dao::create_table<Person>(); // 尝试创建 Person 表
if (sqlError.type() == QSqlError::NoError)
{
qDebug() << "表创建成功!";
}
else
{
qDebug() << "表创建失败! 错误信息: " << sqlError.text();
}
}
else
{
sqlError = db.lastError(); // 获取最后一次数据库错误信息
qDebug() << "数据库连接失败!";
qDebug() << "错误信息: " << sqlError.text();
}
}
void MainWindow::insertData()
{
QSqlError daoError;
// 定义 QSharedPointer 智能指针类型,用于存储 Person 对象
typedef QSharedPointer<Person> person_ptr;
// 创建第一个 Person 对象
person_ptr p1;
p1.reset(new Person());
p1->name = "Tom";
p1->age = 53;
// 创建第二个 Person 对象
person_ptr p2;
p2.reset(new Person());
p2->name = "Tomy";
p2->age = 24;
// 创建第三个 Person 对象
person_ptr p3;
p3.reset(new Person());
p3->name = "Tony";
p3->age = 23;
// 定义 QVector 存储 Person 智能指针
typedef QVector<person_ptr> person_vector;
person_vector persons;
persons.push_back(p1);
persons.push_back(p2);
persons.push_back(p3);
// 尝试插入数据
daoError = qx::dao::insert(persons);
if (daoError.type() == QSqlError::NoError)
{
qDebug() << "数据插入成功!";
}
else
{
qDebug() << "数据插入失败! 错误信息: " << daoError.text();
}
}
void MainWindow::deleteData()
{
QSqlError daoError;
Person deletePerson;
deletePerson.id = 3;
daoError = qx::dao::delete_by_id(deletePerson);
if (daoError.type() == QSqlError::NoError)
{
qDebug() << "数据删除成功!";
}
else
{
qDebug() << "数据删除成功! 错误信息: " << daoError.text();
}
}
void MainWindow::updateData()
{
QSqlError daoError;
// 获取要更新的记录
Person updatePerson;
updatePerson.id = 2; // 假设第二条数据的id为2,具体根据你的数据模型设置
// 查询数据库,获取第二条数据
daoError = qx::dao::fetch_by_id(updatePerson);
if (daoError.type() != QSqlError::NoError)
{
qDebug() << "查询记录失败! 错误信息: " << daoError.text();
return;
}
// 修改记录的属性
updatePerson.name = "Tommy";
updatePerson.age = 18;
// 尝试更新数据
daoError = qx::dao::update(updatePerson);
if (daoError.type() == QSqlError::NoError)
{
qDebug() << "数据更新成功!";
}
else
{
qDebug() << "数据更新失败! 错误信息: " << daoError.text();
}
}
void MainWindow::selectData()
{
QSqlError daoError;
QList<Person> list_of_person;
// 尝试从数据库中获取所有的 Person 记录
daoError = qx::dao::fetch_all(list_of_person);
if (daoError.type() == QSqlError::NoError)
{
qDebug() << "数据查询成功!";
// 遍历 QList<Person>
for (const Person& person : list_of_person)
{
qDebug() << "ID: " << person.id << ", Name: " << person.name << ", Age: " << person.age;
// 在这里可以执行其他操作
}
}
else
{
qDebug() << "查询所有数据失败! 错误信息: " << daoError.text();
}
}
具体方体查询QxOrm官方文档:QxOrm manual