QxOrm的使用
现在在网上看到的QxOrm教程,都是最基础的,只是使用该库的基本创建函数,并没有深入的介绍其强大的功能。所以我想写一个专栏,详细介绍QxOrm的使用,我会在介绍模块的时候提供对应的例子给大家参考,该篇文章与官方教程相对应,如果您对我写的有不理解的地方,请看官方文档,我这里也不是所有功能都介绍,仅介绍关系型数据库的连接部分,非关系型的请到官网查看。
本篇文章使用的数据库是sqlite,使用的可视化软件是dbeaver。
不做太多的截图,代码在gitee上都有展示,也会贴出具体的代码供学习,博主技术不强,学历不高,如果有问题,请联系我,我会及时修正
● QxOrm源码地址
● QxOrm论坛地址
QxOrm 是一个C++库,旨在为C++用户提供对象关系映射 (ORM)功能。
QxOrm由Lionel Marty开发,他自2003年以来一直担任软件开发工程师
基于每个类的简单C++设置函数(如Java中的HibernateXML映射文件),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的使用。
搭建项目环境
你可以在OxOrm中找到该项目
CMakeLists
cmake_minimum_required(VERSION 3.19) project(QxOrmDemo) set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY_DEBUG ${PROJECT_SOURCE_DIR}/output) set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY_RELEASE ${PROJECT_SOURCE_DIR}/output) set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_DEBUG ${PROJECT_SOURCE_DIR}/output) set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_RELEASE ${PROJECT_SOURCE_DIR}/output) set(CMAKE_CXX_STANDARD 17) set(CMAKE_AUTOMOC ON) set(CMAKE_AUTORCC ON) set(CMAKE_AUTOUIC ON) set(QT_VERSION 5) set(REQUIRED_LIBS Core Gui Widgets PrintSupport Sql ) set(REQUIRED_LIBS_QUALIFIED Qt5::Core Qt5::Gui Qt5::Widgets Qt5::PrintSupport Qt5::Sql) find_package(Qt${QT_VERSION} COMPONENTS ${REQUIRED_LIBS} REQUIRED) #自动查找头文件路径函数 macro(FIND_INCLUDE_DIR result curdir) #定义函数,2个参数:存放结果result;指定路径curdir; file(GLOB_RECURSE children "${curdir}/*.hpp" "${curdir}/*.h" ) #遍历获取{curdir}中*.hpp和*.h文件列表 file(GLOB SOURCE_INCLUDE ${children} ) #将文件放入 SOURCE_INCLUDE 中 set(dirlist "") #定义dirlist中间变量,并初始化 foreach(child ${children}) #for循环 string(REGEX REPLACE "(.*)/.*" "\\1" LIB_NAME ${child}) #字符串替换,用/前的字符替换/*h if(IS_DIRECTORY ${LIB_NAME}) #判断是否为路径 list (FIND dirlist ${LIB_NAME} list_index) #判断dirlist是否含有${LIB_NAME} if(${list_index} LESS 0) LIST(APPEND dirlist ${LIB_NAME}) #将合法的路径加入dirlist变量中 else() endif() #结束判断 endif() endforeach() #结束for循环 set(${result} ${dirlist}) #dirlist结果放入result变量中 endmacro() #自动查找源文件路径函数 macro(FIND_SRC_DIR result curdir) file(GLOB_RECURSE children "${curdir}/*.cpp" "${curdir}/*.cc" "${curdir}/*.cxx") file(GLOB SOURCE_SRC ${children} ) set(dirlist "") foreach(child ${children}) string(REGEX REPLACE "(.*)/.*" "\\1" LIB_NAME ${child}) if(IS_DIRECTORY ${LIB_NAME}) list (FIND dirlist ${LIB_NAME} list_index) if(${list_index} LESS 0) LIST(APPEND dirlist ${LIB_NAME}) else() endif() endif() endforeach() set(${result} ${dirlist}) endmacro() #调用函数,指定参数 #自动查找头文件路径函数 macro(FIND_UI_DIR result curdir) #定义函数,2个参数:存放结果result;指定路径curdir; file(GLOB_RECURSE children "${curdir}/*.ui") #遍历获取{curdir}中*.hpp和*.h文件列表 file(GLOB SOURCE_UI ${children} ) #将文件放入 SOURCE_INCLUDE 中 set(dirlist "") #定义dirlist中间变量,并初始化 foreach(child ${children}) #for循环 string(REGEX REPLACE "(.*)/.*" "\\1" LIB_NAME ${child}) #字符串替换,用/前的字符替换/*h if(IS_DIRECTORY ${LIB_NAME}) #判断是否为路径 list (FIND dirlist ${LIB_NAME} list_index) #判断dirlist是否含有${LIB_NAME} if(${list_index} LESS 0) LIST(APPEND dirlist ${LIB_NAME}) #将合法的路径加入dirlist变量中 else() endif() #结束判断 endif() endforeach() #结束for循环 set(${result} ${dirlist}) #dirlist结果放入result变量中 endmacro() FIND_SRC_DIR(SRC_DIR_LIST ${PROJECT_SOURCE_DIR}/src) FIND_INCLUDE_DIR(INCLUDE_DIR_LIST ${PROJECT_SOURCE_DIR}/src) FIND_UI_DIR(UI_DIR_LIST ${PROJECT_SOURCE_DIR}/src) #将INCLUDE_DIR_LIST中路径列表加入工程,包括第三方库的头文件路径 include_directories( ${INCLUDE_DIR_LIST} #INCLUDE_DIR_LIST路径列表加入工程 ${PROJECT_SOURCE_DIR}/third_party/QxOrm/include ${PROJECT_SOURCE_DIR}/third_party/spdlog/include ) if (CMAKE_BUILD_TYPE AND (CMAKE_BUILD_TYPE STREQUAL "Debug")) file(GLOB LIB_ORM ${PROJECT_SOURCE_DIR}/third_party/QxOrm/libd/*.lib) link_directories(${PROJECT_SOURCE_DIR}/thirdParty/QxOrm/libd) file(GLOB LIB_SPDLOG ${PROJECT_SOURCE_DIR}/third_party/spdlog/Debug/*.lib) link_directories(${PROJECT_SOURCE_DIR}/thirdParty/spdlog/Debug) else () file(GLOB LIB_ORM ${PROJECT_SOURCE_DIR}/third_party/QxOrm/lib/*.lib) link_directories(${PROJECT_SOURCE_DIR}/third_party/QxOrm/lib) file(GLOB LIB_SPDLOG ${PROJECT_SOURCE_DIR}/third_party/spdlog/Release/*.lib) link_directories(${PROJECT_SOURCE_DIR}/thirdParty/spdlog/Release) endif () add_compile_options("$<$<C_COMPILER_ID:MSVC>:/utf-8>") add_compile_options("$<$<CXX_COMPILER_ID:MSVC>:/utf-8>") add_executable(${PROJECT_NAME} WIN32 main.cpp ${SOURCE_INCLUDE} ${SOURCE_SRC} ${SOURCE_UI}) #set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>") set_target_properties(${PROJECT_NAME} PROPERTIES CMAKE_MSVC_RUNTIME_LIBRARY_RELEASE "MultiThreaded$<$<CONFIG:Release>:Release>") target_link_libraries(${PROJECT_NAME} ${REQUIRED_LIBS_QUALIFIED}) target_link_libraries(${PROJECT_NAME} ${LIB_ORM} ${LIB_SPDLOG})
main.cpp
#include <QApplication> #include "precompiled.h" #include "person.h" #include "turbo_log.h" void databaseInit() { qx::QxSqlDatabase::getSingleton()->setDriverName("QSQLITE"); qx::QxSqlDatabase::getSingleton()->setDatabaseName("./demo.db"); qx::QxSqlDatabase::getSingleton()->setHostName("localhost"); qx::QxSqlDatabase::getSingleton()->setUserName("root"); qx::QxSqlDatabase::getSingleton()->setPassword(""); QSqlError daoError = qx::dao::create_table<person>(); if (daoError.type() != QSqlError::NoError) { TurboLog::instance().getDailyLogger()->error("Table Member:" + daoError.text().toStdString()); } } int main(int argc, char **argv) { QApplication app(argc, argv); databaseInit(); return app.exec(); }
person.h
#ifndef QXORMDEMO_PERSON_H #define QXORMDEMO_PERSON_H #include "precompiled.h" #include "export.h" #include <QDateTime> class person { public: long id; QString firstName; QString lastName; QDateTime birthDate; }; QX_REGISTER_HPP_APP(person, qx::trait::no_base_class_defined, 0) #endif //QXORMDEMO_PERSON_H
person.cpp
#include "person.h" QX_REGISTER_CPP_APP(person) namespace qx { template <> void register_class(QxClass<person> & t) { t.setName("t_person"); // 类映射的表名 t.id(& person::id, "id");// 将id注册为主键 long 的时候会注册成自增主键 t.data(& person::firstName, "first_name");//person::firstName注册为表first_name列 t.data(& person::lastName, "last_name"); t.data(& person::birthDate, "birth_date"); } }
我的项目使用了日志库spdlog作为日志输出,这里不做详细介绍。
上面的例子主键是long默认自增的,如果你需要其他主键的话
使用其他类型主键
author.h
#ifndef _QX_BLOG_AUTHOR_H_ #define _QX_BLOG_AUTHOR_H_ #include "precompiled.h" #include "export.h" #include <QString> class author { QX_REGISTER_FRIEND_CLASS(author) public: QString m_id; QString m_name; }; QX_REGISTER_PRIMARY_KEY(author, QString) QX_REGISTER_HPP_APP(author, qx::trait::no_base_class_defined, 0) #endif // _QX_BLOG_AUTHOR_H_
author.cpp
#include "author.h" QX_REGISTER_CPP_APP(author) namespace qx { template <> void register_class(QxClass<author> & t) { t.id(&author::m_id, "m_id"); t.data(& author::m_name, "m_name"); } }
这里的QX_REGISTER_PRIMARY_KEY宏就是定义非long主键的时候使用的。
如果你的类成员变量是私有的或者是保护的,则需要使用QX_REGISTER_FRIEND_CLASS来声明一些友元类。不过我这里都是public,QX_REGISTER_FRIEND_CLASS宏也可以不使用。
使用复合主键
author2.h
#ifndef QXORMDEMO_AUTHOR2_H #define QXORMDEMO_AUTHOR2_H #include "precompiled.h" #include "export.h" #include <QString> #include <tuple> class author2 { public: typedef std::tuple<QString, long, QString> type_composite_key; static QString str_composite_key() { return "author_id_0|author_id_1|author_id_2"; } type_composite_key m_id; QString m_name; QDate m_birthdate; }; QX_REGISTER_PRIMARY_KEY(author2, author2::type_composite_key) QX_REGISTER_HPP_APP(author2, qx::trait::no_base_class_defined, 0) #endif //QXORMDEMO_AUTHOR2_H
author2.cpp
#include "author2.h" QX_REGISTER_CPP_APP(author2) namespace qx { template <> void register_class(QxClass<author2> & t) { t.id(& author2::m_id, author2::str_composite_key()); t.data(& author2::m_name, "name"); t.data(& author2::m_birthdate, "birthdate"); } }
这样就可以建表成功。具体的可以使用可视化工具查看对应的db文件。