ORM für C++: Vergleich und Anwendungsbeispiele
Im Gegensatz zu Sprachen mit dynamischer Typisierung (Python, PHP) verfügt C++ nicht über eine eingebaute Unterstützung für Reflexion und Metaprogrammierung, die ausreicht, um ein "magisches" ORM zu erstellen. Dennoch gibt es mehrere leistungsstarke Lösungen, die die Arbeit mit Datenbanken automatisieren. In diesem Artikel vergleichen wir drei beliebte Bibliotheken: ODB, SOCI und SQLiteCpp, und geben Beispiele für ihre Verwendung.
Vergleichskriterien
Bei der Auswahl eines ORM für C++ sollte man auf Folgendes achten:
- Art der Codegenerierung — externer Generator oder C++-Vorlagen.
- DBMS-Unterstützung — SQLite, PostgreSQL, MySQL, Oracle.
- Leistung — Overhead durch die Abbildung.
- Integrationskomplexität — ist ein separater Build-Schritt erforderlich.
1. ODB — Industrielles ORM für C++
ODB ist ein kommerzielles ORM (mit einer kostenlosen Version für Open-Source), das auf der Codegenerierung aus annotierten Header-Dateien basiert. Es unterstützt relationale Datenbanken (SQLite, PostgreSQL, MySQL, Oracle) und sogar NoSQL (MongoDB).
Beispiel mit ODB (SQLite)
Zunächst deklarieren wir eine Entitätsklasse:
#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_;};Verwendung:
#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();}Vorteile: vollständiges Objektmodell, Unterstützung für Beziehungen, Lazy Loading. Nachteile: Codegenerator erforderlich (Build-Schritt), kommerzielle Lizenz.
2. SOCI — Leichtgewichtige "Data Access Layer"
SOCI ist kein vollwertiges ORM, sondern eine Bibliothek für die Arbeit mit SQL aus C++, die eine bequeme Syntax zum Ausführen von Abfragen und zum Abbilden von Ergebnissen bietet. Sie funktioniert mit SQLite, PostgreSQL, MySQL, Oracle und ODBC.
Beispiel mit 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)";
// Einfügen sql << "INSERT INTO person (name, age) VALUES (:name, :age)", soci::use("Bob"), soci::use(25);
// Abfrage mit Abbildung in eine Struktur 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; }}Vorteile: einfache Integration, keine Codegenerierung, Unterstützung für Prepared Statements. Nachteile: keine automatische Objektabbildung