QxOrm 是一个 C++ 库,旨在为 C++ 用户提供对象关系映射 (ORM) 功能。
基于每个类的简单 C++ 设置函数(如 Java 中的 Hibernate XML 映射文件),QxOrm 库提供以下功能:
持久性: 支持最常见的数据库,如 SQLite、MySQL、PostgreSQL、Oracle、MS SQL Server、MongoDB(具有 1-1、1-n、n-1 和 n-n 关系);
序列化: JSON、二进制和 XML 格式;
反射(或自省): 动态访问类定义、检索属性和调用类方法;
HTTP Web 服务器: 独立的多线程 HTTP 1.1 Web 服务器(支持 SSL/TLS、持久连接、cookie、会话、分块响应、URL 调度程序/路由);
JSON API: 与 C++/Qt 以外的其他技术(REST Web 服务、QML 应用程序、脚本语言)的互操作性。
QxOrm 依赖于 Qt(从 4.5.0 版开始)和 boost(从 1.38 版开始,默认情况下只需要头文件 *.hpp)
下载QxOrm 工程,地址:https://github.com/QxOrm/QxOrm
编译QxOrm 工程,推荐使用Mingw编译,使用QtCreator打开QxOrm 的工程,如下所示:
编译完之后,会在QxOrm\lib目录下生成链接库,如下所示:
创建一个示例User工程
# User.pro
# 通过下面这个脚本配置好QxOrm
include(./QxOrm/QxOrm.pri)
# 设置好QxOrm链接库目录和文件包含
INCLUDEPATH += F:/QxOrm/include
LIBS += -LF:\QxOrm\lib
# 设置好QxOrm对应的动态链接库
CONFIG(debug, debug|release) {
TARGET = Demo
LIBS += -l"QxOrmd"
} else {
TARGET = Demo
LIBS += -l"QxOrm"
})
DEFINES += _BUILDING_QX_DEMO
QT -= gui
# 定义好预编译文件
!contains(DEFINES, _QX_NO_PRECOMPILED_HEADER) {
PRECOMPILED_HEADER = ./precompiled.h
} # !contains(DEFINES, _QX_NO_PRECOMPILED_HEADER)
CONFIG += c++11 console
CONFIG -= app_bundle
DEFINES += QT_DEPRECATED_WARNINGS
SOURCES += \
main.cpp \
user.cpp
# Default rules for deployment.
qnx: target.path = /tmp/$${TARGET}/bin
else: unix:!android: target.path = /opt/$${TARGET}/bin
!isEmpty(target.path): INSTALLS += target
HEADERS += \
export.h \
precompiled.h \
user.h
User.h
// User.h
#ifndef USER_H
#define USER_H
class QX_DEMO_DLL_EXPORT User{
//在 QxOrm 上下文中注册的 4 个属性id,name,age,capacity
public:
int id;
QString name;
int age;
double capacity;
User(): id(1){} //初始化id为1
virtual ~User(){}
};
QX_REGISTER_PRIMARY_KEY(User, int) // 定义主键的类型
/**
QX_REGISTER_HPP_QX_DEMO宏是在 QxOrm 上下文中注册 'User' 类所必需的
参数 1:要注册的当前类 => 'User'
参数 2 : 基类,如果没有基类,使用 qx trait => 'qx::trait::no_base_class_defined'
参数 3 : 序列化引擎用来提供“上升兼容性”的类版本
*/
QX_REGISTER_HPP_QX_DEMO(User, qx::trait::no_base_class_defined, 0)
typedef std::shared_ptr<User> User_ptr;
typedef qx::QxCollection<int, User_ptr> List_user;
#endif // USER_H
export.h && precompiled.h
// export.h
#ifndef EXPORT_H
#define EXPORT_H
#ifdef _BUILDING_QX_DEMO
#define QX_DEMO_DLL_EXPORT QX_DLL_EXPORT_HELPER
#else
#define QX_DEMO_DLL_EXPORT QX_DLL_IMPORT_HELPER
#endif
#ifdef _BUILDING_QX_DEMO
#define QX_REGISTER_HPP_QX_DEMO QX_REGISTER_HPP_EXPORT_DLL
#define QX_REGISTER_CPP_QX_DEMO QX_REGISTER_CPP_EXPORT_DLL
#else
#define QX_REGISTER_HPP_QX_DEMO QX_REGISTER_HPP_IMPORT_DLL
#define QX_REGISTER_CPP_QX_DEMO 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
User.cpp
#include "precompiled.h" //带有 '#include ' 和 '#include "export.h"' 的预编译头文件
#include "user.h"
#include <QxOrm_Impl.h> // 自动内存泄漏检测和提升序列化导出宏
QX_REGISTER_CPP_QX_DEMO(User) // 这个宏是在 QxOrm 上下文中注册 'User' 类所必需的
namespace qx{
template <> void register_class(QxClass<User> &t){
t.setName("user"); // 'User' C++ 类映射到 'user' 数据库表
t.id(&User::id, "id"); // Register 'User::id' <=> primary key in your database
t.data(&User::age, "age"); // Register 'User::age' property mapped to 'age' database column name
t.data(&User::name, "name"); // Register 'User::name' property mapped to 'name' database column name
t.data(&User::capacity, "capacity"); // Register 'User::capacity' property mapped to 'capacity' database column name
}
}
下面从连接数据库到普通的增删改查讲解如何使用QxOrm库,这些操作为了方便都在main函数中操作,(CRUD的库函数都在qx::dao::xxx接口中,本文章只做部分函数的说明,更多的说明请参考文档)
//main.cpp
qx::QxSqlDatabase::getSingleton()->setDriverName("QMYSQL"); //这里可以是任意支持的数据库驱动
qx::QxSqlDatabase::getSingleton()->setDatabaseName("testOrm");
qx::QxSqlDatabase::getSingleton()->setHostName("localhost");
qx::QxSqlDatabase::getSingleton()->setUserName("root");
qx::QxSqlDatabase::getSingleton()->setPassword("root");
qx::QxSqlDatabase::getSingleton()->setFormatSqlQueryBeforeLogging(true);
qx::QxSqlDatabase::getSingleton()->setDisplayTimerDetails(true);
//main.cpp
//根据User类在数据库中创建对应的表,字段名就是在User中定义的属性,且默认主键是自增的
QSqlError daoError = qx::dao::create_table<User>(); //专门为SQLITE服务,其他数据库不建议,为了方便暂且这么用
User_ptr user_1, user_2;
user_1.reset(new User);
user_2.reset(new User);
user_1->name = "zs";
user_1->age = 23;
user_1->capacity = 1000000;
user_2->name = "ls";
user_2->age = 21;
user_2->capacity = 99;
daoError = qx::dao::insert(users, &db); //插入操作
daoError = qx::dao::save(users, &db); //插入或更新
User_ptr user_del;
user_del.reset(new User());
user_del->id = 1;
daoError = qx::dao::delete_by_id(user_del); //据id删除数据
//还有其他函数delete_by_qery(),delete_all()....
User_ptr user_2;
user_2.reset(new User);
user_2->id = 2; //更新id为2的数据
user_2->age = 23;
user_2->name = "laowang";
user_2->capacity = 100;
daoError = qx::dao::update(user_2);
//第一种方法-执行原生的sql语句
List_user list_user;
qx_query querySql("select * from user");
daoError = qx::dao::execute_query(querySql, list_user);
List_user::iterator it = list_user.begin();
while(it != list_user.end()){
qDebug() << "id:" << it.i->t().second->id;
qDebug() << "name:" << it.i->t().second->name;
qDebug() << "age:" << it.i->t().second->age;
qDebug() << "capacity:" << it.i->t().second->capacity;
it++;
}
//第二种方法-fetch_xxx
qx::dao::fetch_all(list_user);
// 当然还有其他很多函数:fetch_by_id(),fetch_by_query()....
..
//占位符形式
QList<User> list_of_wang;
qx::QxSqlQuery query("WHERE user.name = :name"); //默认前面是 select * from user
query.bind(":name","老王");
daoError = qx::dao::fetch_by_query(query,list_of_wang);
//占位符的变体
qx_query query;
query.where("user.name").isEqualTo("老王")
.and_("age").isGreaterThan(20)
.and_("capacity").isLessThan(90);
/**
* 上面语句生成的sql语句
* SELECT user.id AS user_id_0, user.age AS user_age_0, user.name AS user_name_0, user.capacity AS user_capacity_0
FROM user
WHERE user.name = :user_name_1_0
AND age > :age_3_0
AND capacity < :capacity_5_0
*/
daoError = qx::dao::fetch_by_query(query,list_of_wang);
for (long l = 0; l < list_of_wang.count(); l++)
{
/* here we can work with the collection provided by database */
}
//查询自己关心的字段,默认是查询指定表的所有列,指定关系可以查询自己指定的列
//定义一个关系
QStringList relations = QStringList() << "-{name,capacity}" << "{age}";//获取感兴趣的属性(name,capacity),如果没有关系默认是查询一个表的所有列数据,如果在{}前面加-,表示不要此属性
qx::dao::fetch_by_query_with_relation(relations,query,list_of_wang);
。。。待续