ORM для C++: сравнение и примеры использования
В отличие от языков с динамической типизацией (Python, PHP), C++ не имеет встроенной поддержки рефлексии и метапрограммирования, достаточной для создания "магического" ORM. Тем не менее, существует несколько мощных решений, которые автоматизируют работу с базами данных. В этой статье мы сравним три популярные библиотеки: ODB, SOCI и SQLiteCpp, и приведём примеры их использования.
Критерии сравнения
При выборе ORM для C++ стоит обратить внимание на:
- Тип генерации кода — внешний генератор или шаблоны C++.
- Поддержка СУБД — SQLite, PostgreSQL, MySQL, Oracle.
- Производительность — накладные расходы на отображение.
- Сложность интеграции — требуется ли отдельный шаг сборки.
1. ODB — промышленный ORM для C++
ODB — это коммерческий (с бесплатной версией для open-source) ORM, основанный на генерации кода из аннотированных заголовочных файлов. Он поддерживает реляционные базы данных (SQLite, PostgreSQL, MySQL, Oracle) и даже NoSQL (MongoDB).
Пример с ODB (SQLite)
Сначала объявляем класс-сущность:
#include <odb/core.hxx>
#pragma db object
class 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 — легковесный "data access layer"
SOCI — это не полноценный ORM, а библиотека для работы с SQL из C++, которая предоставляет удобный синтаксис для выполнения запросов и отображения результатов. Она работает с 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;
}
}
Плюсы: лёгкая интеграция, нет генерации кода, поддержка prepared statements. Минусы: нет автоматического отображения объектов, требуется писать SQL вручную.
3. SQLiteCpp — минималистичная обёртка для SQLite
SQLiteCpp — это header-only библиотека, предоставляющая C++ API для SQLite. Она не является ORM в полном смысле, но автоматизирует управление ресурсами и предоставляет удобные классы для работы с БД.
Пример с SQLiteCpp
#include <SQL