ODB: C++ Object-Relational Mapping (ORM)

ODB is an open-source, cross-platform, and cross-database object-relational mapping (ORM) system for C++. It allows you to persist C++ objects to a relational database without having to deal with tables, columns, or SQL and without manually writing any mapping code. ODB supports MySQL, SQLite, PostgreSQL, Oracle, and Microsoft SQL Server relational databases as well as C++98/03 and C++11 language standards. It also comes with optional profiles for Boost and Qt which allow you to seamlessly use value types, containers, and smart pointers from these libraries in your persistent C++ classes.

The following example shows an ordinary C++ class on the left and its persistent version on the right.

  #pragma db object
  class person
  {
    ...
  private:
    friend class odb::access;
    person () {}

    #pragma db id
    string email_;

    string name_;
    unsigned short age_;
  };
 
  class person
  {
    ...
  private:




    string email_;

    string name_;
    unsigned short age_;
  };

ODB is not a framework. It does not dictate how you should write your application. Rather, it is designed to fit into your style and architecture by only handling C++ object persistence and not interfering with any other functionality. As you can see, existing classes can be made persistent with only a few modifications. In particular, a persistent class can be declared without the default constructor, existing accessor and modifier functions can be automatically used to access the data members, and ODB pragmas can be moved out of the class and into a separate header, making the object-relational mapping completely non-intrusive. Support for automatic database schema evolution further allows you to treat ODB persistent objects like any other C++ classes in your application.

Given the above declarations, we can perform various database operations with objects of the person class using SQLite as an example:

  odb::sqlite::database db ("people.db");

  person john ("john@doe.org", "John Doe", 31);
  person jane ("jane@doe.org", "Jane Doe", 29);

  odb::transaction t (db.begin ());

  db.persist (john);
  db.persist (jane);

  typedef odb::query<person> person_query;

  for (person& p: db.query<person> (person_query::age < 30));
    cerr << p << endl;

  jane.age (jane.age () + 1);
  db.update (jane);

  t.commit ();

For the complete version of the above code fragment as well as a detailed explanation of each line, refer to the Hello World Example in the ODB Manual.

Using ODB for object persistence has the following advantages:

ODB is highly flexible and customizable. It can either completely hide the relational nature of the underlying database or expose some of the details as required. For example, you can automatically map basic C++ types to suitable SQL types, generate the relational database schema for your persistent classes, and use simple, safe, and yet powerful object query language instead of SQL. Or you can assign SQL types to individual data members, use the existing database schema, and execute native SQL queries. In fact, at an extreme, ODB can be used as just a convenient way to handle results of native SQL queries.

The C++ code that performs the conversion between persistent classes and their database representation is automatically generated by the ODB compiler. The ODB compiler is a real C++ compiler except that it produces C++ instead of assembly or machine code. In particular, it is not an ad-hoc header pre-processor that is only capable of recognizing a subset of C++. ODB is capable of parsing any standard C++ code.

The ODB compiler uses the GCC compiler frontend for C++ parsing and is implemented using the new GCC plugin architecture. While ODB uses GCC internally, its output is standard C++ which means that you can use any C++ compiler to build your application.