ORM for C++: Comparison and Usage Examples

Online Python Trainer for Beginners

Learn Python easily without overwhelming theory. Solve practical tasks with automatic checking, get hints in Russian, and write code directly in your browser — no installation required.

Start Course
```html

ORM for C++: Comparison and Examples



In the world of C++, working with databases has historically been more low-level than in languages like Python or Java. However, modern projects require convenience and productivity, so developers are increasingly turning to ORM (Object-Relational Mapping). ORM for C++ allows you to work with tables as regular C++ objects, automatically generate SQL queries, and manage schema migrations. In this article, we will look at five popular libraries: ODB, SQLiteCpp, SOCI, cppdb, and sqlpp11, compare their features, and provide practical examples.



1. ODB — The Corporate Standard



ODB is a powerful ORM framework for C++ that supports many DBMS: MySQL, PostgreSQL, SQLite, Oracle, SQL Server. The main feature is code generation: you describe the model in a header file with annotations, and the ODB compiler (odb) creates the code for working with the database.



// person.hxx#pragma once#include <string>#include <odb/core.hxx>

#pragma db objectclass Person {public: Person() {} Person(const std::string& name, int age) : name_(name), age_(age) {}

const std::string& getName() const { return name_; } int getAge() const { return age_; }

private: friend class odb::access; #pragma db id auto unsigned long id_; std::string name_; int age_;};


After running odb -d mysql person.hxx, files with the implementation are generated. Then we use the standard pattern:



#include <odb/database.hxx>#include <odb/mysql/database.hxx>#include "person-odb.hxx"

int main() { auto db = std::make_shared<odb::mysql::database>("user", "pass", "mydb"); Person p("Alice", 30); db->persist(p); // Loading auto loaded = db->load<Person>(1); return 0;}


Pros: full ORM, migration support, lazy loading, transaction handling. Cons: complex setup, need for code generation, heavyweight for small projects.



2. SQLiteCpp — Lightweight and Simple



SQLiteCpp is a C++ RAII-style wrapper over SQLite3. It is not a full-fledged ORM, but it provides a convenient interface for working with queries.



#include <SQLiteCpp/Database.h>#include <SQLiteCpp/Statement.h>

int main() { SQLite::Database db("test.db", SQLite::OPEN_READWRITE | SQLite::OPEN_CREATE); db.exec("CREATE TABLE IF NOT EXISTS person (id INTEGER PRIMARY KEY, name TEXT, age INT)"); SQLite::Statement insert(db, "INSERT INTO person (name, age) VALUES (?, ?)"); insert.bind(1, "Bob"); insert.bind(2, 25); insert.exec(); // Reading SQLite::Statement query(db, "SELECT * FROM person WHERE age > ?"); query.bind(1, 20); while (query.executeStep()) { std::cout << query.getColumn(1) << " " << query.getColumn(2) << ""; } return 0;}


Pros: minimalistic, no code generation required, works only with SQLite. Cons: no object mapping, manual SQL writing.



3. SOCI — Universal Abstraction Layer



SOCI (The C++ Database Access Library) is not an ORM in the pure sense, but an abstraction over different DBMS (SQLite, PostgreSQL, MySQL, Oracle). It provides a convenient syntax for executing queries and binding results to C++ structures.



#include <soci/soci.h>#include <soci/sqlite3.h>

struct Person { int id; std::string name; int age;};

int main() { soci::session sql(soci::sqlite3, "test.db"); sql << "CREATE TABLE person (id INTEGER PRIMARY KEY, name TEXT, age INT)"; Person p{1, "Charlie", 35}; sql << "INSERT INTO person (id, name, age) VALUES (:id, :name ```

Recommendations