ODB - compiler-based ORM for C++
If you have read my earlier posts on parsing C++ with GCC plugins (Part 1, Part 2, and Part 3), then you might remember that I mentioned a secret project that I have been working on. You might also have noticed that I’ve been neglecting this blog lately. Well, today is the day to unveil this secret project, which is what kept me busy for these past several months.
The project is called ODB and it is a compiler-based 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.
You might have already used other ORM implementations for C++. And if you have been exposed to ORM systems for other mainstream languages, such as Hibernate for Java, the C++ versions must have felt pretty inferior. The major sore point is the need to write some sort of serialization or registration code for each and every data member in each and every persistent class. Forgot to register a new member? Say good bye to your data.
The primary goal of the ODB project is to change that. It takes a different approach and uses a C++ compiler to parse your classes and automatically generate the database conversion code. Or, more precisely, it uses the new GCC plugin architecture to re-use the tried and tested GCC compiler frontend to parse C++. As a result, ODB is capable of handling any C++ code. While the ODB compiler uses GCC internally, its output is standard C++ which means that you can use any C++ compiler to build the generated code and your application.
Let’s see how a persistent class declaration will look in ODB:
#pragma db object class person { ... private: friend class odb::access; person (); #pragma db id auto unsigned long id_; string first_; string last_; 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.
Given the above class, we can perform various database operations with its objects:
person john ("John", "Doe", 31); person jane ("Jane", "Doe", 29); transaction t (db.begin ()); db.persist (john); db.persist (jane); result r (db.query<person> (query::age < 30)); copy (r.begin (), r.end (), ostream_iterator<person> (cout, "n")); jane.age (jane.age () + 1); db.update (jane); t.commit ();
ODB is written in portable C++ and you should be able to use it with any modern C++ compiler. We have tested this release on GNU/Linux (x86/x86-64), Windows (x86/x86-64), Mac OS X, and Solaris (x86/x86-64/SPARC) with GNU g++ 4.2.x-4.5.x, MS Visual C++ 2008 and 2010, and Sun Studio 12. The dependency-free ODB compiler binaries are available for all of the above platforms. The initial release only supports MySQL as the underlying database. Support for other database systems is in the works.
Well, I hope this sounds as exciting to you as it does to me. And I hope you will enjoy playing around with ODB (check out the Hello World Example if nothing else) while I go catch up on some sleep.
September 30th, 2010 at 7:55 am
How do you handle relationships? I couldn’t find anything on the docs.
September 30th, 2010 at 8:04 am
There is no direct support for relationships in this version but it is coming in the next release. The to-one relationship can be emulated by storing the object id and then manually loading the other end of the relationship. The to-many relationship is harder since there is no direct support for storing sequences either (also coming in the version).
September 30th, 2010 at 10:48 am
Can it persist classes using STL data types such as Map or is it limited to the basic C++ types in this version?
September 30th, 2010 at 11:05 am
There is no built-in support for persisting collections in this version. What you could do in the meantime is save them in a single database cell as, say, a space-separated list of values. This will not work too well if you have thousands of values, but otherwise, it is quite easy to do in ODB. See the ‘mapping’ example for some sample code.