一、介绍和库安装
ODB是一个开源、跨平台、跨数据库的C++对象关系映射(ORM)系统。它可以将C++对象持久化到关系数据库中,而不必处理复杂的表、列或SQL的直接操作。同时,它支持使用命令或Cmake进行直接的代码生成,而无需手动编写任何映射代码。ODB支持SQLite、PostgreSQL、MySQL、Oracle和Microsoft SQL Server关系数据库。它还附带支持了Boost和Qt的可选配置文件,并支持在持久C++类中无缝使用这些库中的值类型、容器和智能指针。一些更具体的功能,请参看ODB的官网“https://codesynthesis.com/products/odb/”中的文档说明。
其安装的过程如下:
- 安装Sqlite3的数据库开发支持
sudo apt-get install libsqlite3-dev #数据库 - 安装ODB的开发支持
sudo apt install odb #数据库对象关系映射框架
二、应用例程
下面是一个相对简单的例程:
//CMakeLists.txt文件
cmake_minimum_required(VERSION 3.16)
project(odb-create-db LANGUAGES CXX)
set(CMAKE_AUTOMOC ON)
set(CMAKE_INCLUDE_CURRENT_DIR ON)
set(CMAKE_CXX_COMPILER "g++")
set(CMAKE_CXX_FLAGS "-std=c++11 -g")
MESSAGE( STATUS "CMAKE_GENERATOR: ${CMAKE_INCLUDE_CURRENT_DIR}")
MESSAGE( STATUS "CMAKE_CUR_SRC_DIR: ${CMAKE_CURRENT_SOURCE_DIR}")
find_package(Qt6 6.5 REQUIRED COMPONENTS Core)
ADD_CUSTOM_COMMAND (OUTPUT demo-odb.cxx demo-odb.hxx demo-odb.ixx
DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/demo.h
COMMAND odb
ARGS --std c++11 --database sqlite --generate-query --generate-schema ${CMAKE_CURRENT_SOURCE_DIR}/demo.h
)
set_property(SOURCE demo-odb.cxx PROPERTY SKIP_AUTOMOC ON)
set_property(SOURCE demo-odb.hxx PROPERTY SKIP_AUTOMOC ON)
add_executable(odb-create-db main.cpp
demo.h
${CMAKE_CURRENT_BINARY_DIR}/demo-odb.cxx)
target_link_libraries(odb-create-db odb odb-sqlite)
include(GNUInstallDirs)
install(TARGETS odb-create-db
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
)
//数据库表demo的映射文件demo.h
#ifndef DEMO_H
#define DEMO_H
#include <memory>
#include <odb/core.hxx>
#include <string>
#pragma db object pointer(std::shared_ptr) session
class Demo {
public:
explicit Demo(const std::string &name) : m_userName(name) {}
public:
void setName(const std::string &name) { m_userName = name; }
unsigned int userId() const { return m_userId; }
std::string userName() const { return m_userName; }
private:
friend class odb::access;
Demo() {}
private:
#pragma db id auto
unsigned int m_userId = 0;
std::string m_userName = "";
};
#endif // DEMO_H
//主文件main.cpp
#include <iostream>
#include <memory>
#include <odb/connection.hxx>
#include <odb/database.hxx>
#include <string>
#include <odb/connection.hxx>
#include <odb/schema-catalog.hxx>
#include <odb/sqlite/database.hxx>
#include <odb/transaction.hxx>
#include <odb/session.hxx>
#include <odb/transaction.hxx>
#include "demo-odb.hxx"
#include "demo.h"
inline std::unique_ptr<odb::database> create_database(int &argc, char *argv[]) {
using namespace std;
using namespace odb::core;
unique_ptr<database> db(new odb::sqlite::database(argc, argv, false, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE));
{
connection_ptr c(db->connection());
c->execute("PRAGMA foreign_keys=OFF");
transaction t(c->begin());
schema_catalog::create_schema(*db);
t.commit();
c->execute("PRAGMA foreign_keys=ON");
}
return db;
}
using namespace std;
using namespace odb::core;
int main(int argc, char *argv[]) {
try {
std::unique_ptr<odb::database> db(create_database(argc, argv));
{
shared_ptr<Demo> d1(new Demo("alice"));
shared_ptr<Demo> d2(new Demo("mary"));
transaction t(db->begin());
db->persist(d1);
db->persist(d2);
t.commit();
}
{
shared_ptr<Demo> d3(new Demo("dog1"));
shared_ptr<Demo> d4(new Demo("dog2"));
transaction t(db->begin());
db->persist(d3);
db->persist(d4);
t.commit();
}
{
typedef odb::query<Demo> query;
typedef odb::result<Demo> result;
session s;
transaction t(db->begin());
result r(db->query<Demo>(query::userName == "John" || query::userName == "Jane"));
std::cout << "query result, count = " << r.empty() << std::endl;
for (auto it(r.begin()); it != r.end(); ++it) {
cout << it->userName() << ' ' << it->userId() << endl;
}
t.commit();
}
} catch (const std::exception &e) {
std::cerr << e.what() << std::endl;
return EXIT_FAILURE;
}
return 0;
}
这个例程提供了数据库、表的创建,以及数据的插入和对相关数据的过滤查询。代码并不复杂,大家运行一下即可明白。
三、细节问题
在实际的应用中遇到几个细节的问题,需要注意一下:
- 生成表的字段名和变量与属性的关系
一般来说是变量名称不带下划线的部分或属性名称,比如m_userName,生成的字段就是useName,last_,生成的字段是last - 版本的支持
目前来看,ODB版本只支持到了C++11(或许没有使用更新的版本),在编译选项中使用C++17会报编译错误 - 包含生成的odb编译单元文件
在CmakeLists.txt中的add_executable内一定要记得增加${CMAKE_CURRENT_BINARY_DIR}/xxx-odb.cxx(前面的xxx代表工程中的实际的映射类名称,后面的cxx代表是C++编译单元)。否则的话可能无法自动生成CMakeLists.txt中OUTPUT路径下的文件。 - 库文件和表的生成
在实际的操作中,使用代码生成了数据库和表,可以用代码进行各种操作,但使用SQLite viewer却无法打开。但使用测试例程的生成的则没有问题。后来经过反复查找测试才发现是SQLite viewer无法自动匹配相关Sqlite数据库的原因。只要打开一个正常的Sqlite数据库,然后再打开生成的不能直接打开的数据,即可正常打开。 - 编译中的类型转换问题
如果在实际应用的类(或封装数据库映射类)中未包含相关的xxx-odb.hxx则会出现类型转换的错误,特别是使用智能指针时,可能会出现,数据类型的不匹配的错误。如:
“error: invalid initialization of reference of type ‘Users* const&’ from expression of type ‘const std::shared_ptr’”或
“error: invalid use of incomplete type ‘struct odb::query_selector_impl<Users, odb::id_common, odb::class_other>’”
四、扩展
在上面的应用中,是一种小规模的场景下。如果需要创建的表工库比较多的情况下,官网也提供了更好的示例方法,在https://github.com/BtbN/OdbCmake/tree/master的cmake/Modules中有两个cmake模块文件即findODB.cmake和useODB.cmake。大家可能参考它们写出更复杂的Sqlite的ORM映射方法。
具体的文件内容就不再贴上来了,有兴趣可以去下载。示例工程也比较简单明了,相信可以在很短的时间内掌握相关的应用方式。
五、总结
其实用C++来开发数据库应用是一种非常不划算的工作,做为一种较低级的语言,天生对数据库的支持就不好操作。虽然有ODB这种ORM框架,但如果和其它语言相比,还是要复杂的多。但在C++开发中,有些场景下数据库的应用还是不可避免的,特别是Sqlite这种小型数据库。所以,还是要掌握一些ORM的相关框架,至少比原生访问数据库要简单很多。
C++中ODB ORM框架应用解析

3066

被折叠的 条评论
为什么被折叠?



