ORM
ORM 全稱是 Object Relational Mapping(對象關系映射),是一種程序設計技術,用於實現面向對象編程語言里不同類型系統的數據之間的轉換。從效果上說,它其實是創建了一個可在編程語言里使用的“虛擬對象數據庫”。
面向對象是從軟件工程基本原則(如耦合、聚合、封裝)的基礎上發展起來的,而關系數據庫則是從數學理論發展而來的,兩套理論存在顯著的區別。為了解決這個不匹配的現象,對象關系映射技術應運而生。
簡單理解,ORM 就是在數據庫和對象之間作了一個映射:
-
數據庫的表(table) –> 類(class)
-
記錄(record,行數據)–> 對象(object)
-
字段(field)–> 對象的屬性(attribute)
ORM 的優缺點
優點:
- ORM 提供了一種面向對象的查詢語言,這使得開發者可以專注於對象模型,而不必關心數據庫結構或 SQL 語義。
- ORM 提供了大量的服務,開發者只需要關注業務邏輯,而不是重復的 CRUD(Create、Read、Update、Delete)操作,這可以減少大量的代碼。
- ORM 將迫使你使用 MVC 風格,這通常會使代碼更加簡潔、更容易理解。
- ORM 有現成的工具,很多功能可以自動完成,比如預處理、事務等。
- ORM 對數據庫進行了抽象,因此從一種數據庫切換到另一種(例如:從 MySQL 到 PostgreSQL)會很容易。
缺點:
- 無論是什么 ORM 框架,都需要花費相當大的精力去學習和理解。
- ORM 抽象掉了數據庫層,開發者無法了解底層數據庫(和 SQL)的相關操作。
- 對於復雜的查詢,ORM 要么難以實現,要么性能不如原生的 SQL。
主流的 ORM 框架
目前為止,C++ 中主流的 ORM 框架有以下幾個:
- LiteSQL:https://litesql.org/
- ODB:https://www.codesynthesis.com/products/odb/
- QxOrm:https://www.qxorm.com/qxorm_en/home.html
- Wt::Dbo:https://www.webtoolkit.eu/wt/doc/tutorial/dbo.html
其中,LiteSQL 和 ODB 不依賴於特定的框架,而 QxOrm 依賴於 Qt,Wt::Dbo 依賴於 Wt。
綜合考慮,如果是純 C++ 開發,可以選擇使用 ODB。它擁有大量的用戶群體,(相比 LiteSQL)技術支持好,(相比 QxOrm)編譯時間短,(相比 Wt::Dbo)提供了更多的特性,更重要的是它易於使用,並且提供了很全面的文檔。
當然,如果是 Qt 開發,也可以選擇使用 QxOrm。它幾乎支持所有的數據庫,並且也有良好的文檔。除此之外,它還提供了一個圖形編輯器 - QxEntityEditor,可以很方便地以圖形方式來管理數據模型。
關於 QxOrm
QxOrm 是一個 C++ 庫,旨在為 C++/Qt 開發人員提供對象關系映射(ORM)功能(類似於 Java 中的 Hibernate,.Net 中的 NHibernate)。
- 主頁:http://www.qxorm.com/qxorm_en/home.html
- 下載:http://www.qxorm.com/qxorm_en/download.html
- 手冊:http://www.qxorm.com/qxorm_en/manual.html
- 在線類文檔:http://www.qxorm.com/doxygen/html/index.html
- GitHub:https://github.com/QxOrm/QxOrm
其主要特性包括:
- 持久性:支持最常見的數據庫,如 SQLite、MySQL、PostgreSQL、Oracle、MS SQL Server、MongoDB(具有 1-1、1-n、n-1 和 n-n 關系)。
- 序列化:JSON、二進制和 XML 格式。
- 反射(或內省):動態訪問類定義、檢索屬性和調用類方法。
- HTTP Web Server:獨立的多線程 HTTP 1.1 web 服務器(支持 SSL/TLS、持久連接、cookie、會話、分塊響應、URL 分發器/路由)。
- JSON API:與 C++/Qt 以外的其他技術的互操作性(REST web 服務、QML 應用程序、腳本語言)。
默認情況下,QxOrm 庫只依賴 QtCore 和 QtSql 模塊。如果啟用 QxOrm HTTP web server 特性,那么還將依賴於 QtNetwork 模塊。除此之外,有些特性還需要依賴 boost(默認禁用)。
編譯 QxOrm
進入 QxOrm 下載頁面 ,選擇最新版本進行下載,目前最新為 QxOrm 1.4.8 。下載完成之后,將 QxOrm 的 zip 包解壓縮。
對一些重點目錄的介紹一下:
- doc:介紹 QxOrm 的相關文檔。
- include:包含了 QxOrm 的所有頭文件(.h)。
- lib:庫目錄,用於存放編譯后的 .lib 和 .dll 文件。
- src:包含了 QxOrm 的所有源文件(.cpp)。
- test:包含了 QxOrm 相關的示例程序。
有關 QxOrm 的各個歷史版本以及各版本的一些特性,都記錄在 changes.txt 文件中,感興趣的話可以大概看一看。
由於源碼包中提供了 CMakeLists.txt、QxOrm.pro 和 QxOrm.sln,所以無論你使用 CMake 還是 Qt Creator,亦或者是 Visual Studio,都能夠快速編譯 QxOrm。
以 Qt Creator 為例,打開 QxOrm.pro 並進行編譯。成功之后,對應的庫會生成到 QxOrm/lib 目錄下。
默認情況下,這會生成共享庫(動態鏈接庫);倘若要生成靜態鏈接庫,需要啟用 QxOrm.pri 中的 _QX_STATIC_BUILD 編譯選項。
QxOrm 使用
QxOrm 幾乎支持所有的主流數據庫,比如 SQLite、MySQL、PostgreSQL、Oracle、MS SQL Server、MongoDB 等。為了快速了解它的用法,我們以 SQLite 為例,來介紹一些常見的數據庫操作(例如:增刪改查)。
先來創建一個名為 User 的項目,項目所在目錄與 QxOrm 解壓目錄同級,可以根據自己的需要調整。項目完整源代碼下載地址。
項目文件
項目文件由 User.pro 表示,它包含了項目中所有的文件列表(頭文件、源文件),以及所有依賴項(QxOrm.pri 文件包含了與 Qt 和 boost 庫的所有依賴項):
1 |
# QxOrm 的通用配置,包含了 Qt 和 boost 庫依賴 |
這里有一個重要的常量 - _BUILDING_USER,通過它可以知道項目是否正在編譯(參見 export.h 和 Windows 下的 DLL 機制 - 導入或導出函數、類…)。
export.h 文件
如果使用過 DLL,相信對此文件並不陌生,它可以管理類、函數 … 的導出/導入。
QxOrm 使用了相同的機制來提供某些功能:因此對於使用 QxOrm 庫的所有項目,export.h 文件是必需的:
1 |
|
預編譯頭文件
預編譯頭文件的作用在於:提高編譯速度。換句話說,使用它能夠減少項目的編譯時間。
QxOrm 使用元編程的概念來提供許多功能,元編程在編譯時成本很高,因此使用 precompiled.h 文件可以更快地編譯項目:
1 |
|
此外,還有一個優點:文件 QxOrm.h 包含了 Qt 和 boost 庫的基本功能,因此,不需要再編寫像 #include <QtCore/QString.h> 這樣的語句來使用 Qt 的 QString 類;同樣地,也不需要編寫像 #include <boost/shared_ptr.hpp> 這樣的語句來使用 boost 庫的智能指針。
定義 User 類
在 C++ 代碼中,User 類對應的是數據庫中的 User 表,而類的屬性對應的是表中的一個字段(列)。因此,C++ 源代碼中的一個 User 類實例對應 User 表中的一條記錄(行),這種機制使得 C++ 源代碼更易於開發和維護。
為 User 類定義三個屬性,id、name 和 age:
1 |
|
QX_REGISTER_HPP_USER 宏是必須的,用於將 User 類注冊到 QxOrm 的上下文中:
- 參數一:表示要注冊的當前類 - User。
- 參數二:基類,如果沒有基類,則使用 qx::trait::no_base_class_defined。
- 參數三:用於序列化的類版本。
在 user.cpp 文件中,需要實現 qx::register_class(),它是一個設置函數:
1 |
|
和 QX_REGISTER_HPP_USER 相同,QX_REGISTER_CPP_USER 宏也是必需的,用於將 User 類注冊到 QxOrm 的上下文中。
基本應用
現在,是時候一展身手了。通過 User 類,來了解 QxOrm 中的一些基本操作:
1 |
#include "precompiled.h" |
這里重點介紹一下 QxOrm_Impl.h,它的作用是檢測內存泄露。如果使用 QxMemLeak 模塊或 boost::serialization 引擎,應該在所有的 *.cpp 中包含它;否則,它便是可選的(非必須)。
運行程序
運行程序,除了會打印一系列的輸出信息之外,還會生成相應的數據庫文件和 JSON 文件。
QxOrm 不會隱藏 SQL 查詢(默認情況下,所有的語句都會顯示),所以在控制台中可以看到執行過程。
1 |
[QxOrm] qx::QxSqlDatabase : create new database connection in thread '0x2554' with key '{652e45d3-7186-4bd6-81d1-9ff32fcff744}' |
如果要查看數據庫 Users.db 的信息,可以使用數據庫可視化工具(例如:Navicat Premium)。
JSON 文件是通過序列化生成的,打開 export_users.json,將會看到相應的數據。
1 |
[ |
文獻資料
QxOrm網站提供了一個用戶手冊。
本文檔的目的是提供用戶指南,以學習如何使用QxOrm庫功能。本手冊適用於正在尋找一種解決方案來管理C ++ / Qt中的持久數據層的開發人員和軟件架構師。要理解本文檔,需要具備C ++和數據庫的技術技能。
注意:可以使用QxEntityEditor應用程序(用於QxOrm庫的圖形編輯器,數據模型設計器和源代碼生成器)快速輕松地定義本手冊/用戶指南中描述的所有功能。QxOrm網站上提供了另一個專門針對QxEntityEditor應用程序的文檔。
數據模型管理工具
QxEntityEditor是QxOrm庫的圖形編輯器:QxEntityEditor提供了一種圖形方法來管理數據模型。QxEntityEditor是多平台的(適用於Windows,Linux和Mac OS X),並為所有環境生成本機代碼:台式機(Windows,Linux,Mac OS X),嵌入式和移動(Android,iOS,Windows Phone,Raspberry Pi等) )。 QxOrm網站上提供了QxEntityEditor應用程序的用戶手冊(文檔)。
QxEntityEditor基於插件,並提供了多種導入/導出數據模型的方式:
- 自動生成C ++持久類(在QxOrm上下文中注冊);
- 自動為SQLite,MySQL,PostgreSQL,Oracle和MS SQL Server生成DDL SQL腳本(數據庫架構);
- 管理每個項目版本(ALTER TABLE,ADD COLUMN,DROP INDEX等)的模式演變;
- 使用 QxService模塊通過網絡傳輸數據模型並快速創建客戶/服務器應用程序;
- 導入用於SQLite,MySQL,PostgreSQL,Oracle和MS SQL Server數據庫的現有數據庫結構(使用ODBC連接或本機驅動程序);
- 因為每個項目都是不同的,所以QxEntityEditor提供了幾種自定義生成文件的方法(尤其是javascript引擎和集成的調試器)。
結束語
由於 QxOrm 可以自動對 Entity 對象與數據庫中的 Table 進行屬性與字段的映射,所以在實際項目中幾乎不需要編寫數據訪問層的代碼,這在很大程度上提高了我們的開發效率。
但 QxOrm 不能解決 SQL 和數據庫的所有問題(沒有一種工具是萬能的),所以有時也需要使用 Qt 的 QtSql 引擎來編寫自己的 SQL 查詢或存儲過程。