C++ ORM:比较与使用示例
与动态类型语言(Python、PHP)不同,C++ 没有内置足够的反射和元编程支持来创建“魔法”ORM。尽管如此,仍有几种强大的解决方案可以自动化数据库操作。在本文中,我们将比较三个流行的库:ODB、SOCI 和 SQLiteCpp,并提供它们的使用示例。
比较标准
在选择 C++ ORM 时,应注意以下几点:
- 代码生成类型——外部生成器或 C++ 模板。
- 数据库支持——SQLite、PostgreSQL、MySQL、Oracle。
- 性能——映射的开销。
- 集成复杂度——是否需要单独的构建步骤。
1. ODB——工业级 C++ ORM
ODB 是一个商业(为开源项目提供免费版本)ORM,基于从带注释的头文件生成代码。它支持关系型数据库(SQLite、PostgreSQL、MySQL、Oracle)甚至 NoSQL(MongoDB)。
ODB 示例(SQLite)
首先声明实体类:
#include <odb/core.hxx>
#pragma db objectclass Person {public: Person(const std::string& name, int age) : name_(name), age_(age) {}
unsigned long id() const { return id_; } const std::string& name() const { return name_; } int age() const { return age_; }
private: friend class odb::access; #pragma db id auto unsigned long id_; std::string name_; int age_;};使用:
#include <odb/database.hxx>#include <odb/sqlite/database.hxx>#include <odb/transaction.hxx>#include "person.hxx"#include "person-odb.hxx"
int main() { auto db = std::make_shared<odb::sqlite::database>("test.db"); odb::transaction t(db->begin());
Person p("Alice", 30); db->persist(p); // INSERT
auto result = db->query<Person>( odb::query<Person>::age > 25); for (const auto& person : result) { std::cout << person.name() << std::endl; } t.commit();}优点:完整的对象模型、支持关系、延迟加载。缺点:需要代码生成器(构建步骤)、商业用途需许可证。
2. SOCI——轻量级“数据访问层”
SOCI 不是一个完整的 ORM,而是一个用于在 C++ 中操作 SQL 的库,它提供了执行查询和映射结果的便捷语法。它支持 SQLite、PostgreSQL、MySQL、Oracle 和 ODBC。
SOCI 示例
#include <soci/soci.h>#include <soci/sqlite3/soci-sqlite3.h>#include <iostream>
struct Person { int id; std::string name; int age;};
int main() { soci::session sql(soci::sqlite3, "test.db"); sql << "CREATE TABLE IF NOT EXISTS person (" "id INTEGER PRIMARY KEY, " "name TEXT, age INTEGER)";
// 插入 sql << "INSERT INTO person (name, age) VALUES (:name, :age)", soci::use("Bob"), soci::use(25);
// 查询并映射到结构体 Person p; soci::indicator ind; sql << "SELECT id, name, age FROM person WHERE id = :id", soci::use(1), soci::into(p.id), soci::into(p.name, ind), soci::into(p.age);
if (ind == soci::i_ok) { std::cout << p.name << " " << p.age << std::endl; }}优点:易于集成、无需代码生成、支持预编译语句。缺点:没有自动对象映射