Menu

en_TutorialDecl

Vaclav Naydionov

Declaring an OR-mapping within a class declaration

For this tutorial Sqlite3 is used, for other DB engines the connection string
in Yb::Session constructor will have to be changed. Let's assume there is a
table named client_tbl with a surrogate primary key and several information
fields (name, e-mail, etc.).

It's easy to construct a class mapped to the table, while the instances of the
class will map to certain rows in that table. When declaring the class make
sure to use Yb::DomainObject as a base class. The mapping itself is done via
macro YB_DECLARE with help of some other macros for certain attributes.

The family of macros YB_COL_* are helpful for declaring attributes, you can
use them to set the class attribute name, the column name, data type, size
etc. The macros may differ by name and by the number of positional parameters.
YB_COL macro – is the most generic one, it accepts more parameters that the
others.

#include "orm/domain_object.h"
#include "orm/domain_factory.h"
#include "orm/schema_decl.h"

class Client: public Yb::DomainObject {

YB_DECLARE(Client, "client_tbl", "client_seq", "client",
    YB_COL_PK(id, "id")
    YB_COL_DATA(dt, "dt", DATETIME)
    YB_COL_STR(name, "name", 100)
    YB_COL_STR(email, "email", 100)
    YB_COL_DATA(budget, "budget", DECIMAL)
    YB_COL_END)

public: 
    int get_info() const { return 42; } 
};

This class declaration can be placed in a header or in a .cpp file. One more
sentence is expected in your .cpp file for the magic to work:

YB_DEFINE(Client)

Class Client is automatically given a few new data members and methods.
There are now mapped properties (id, dt, name, …) at each object of the
class. The properties can be used to access the column data in read and write
modes, as well as to check for absent value (IS NULL).

To control the instances of a mapped classes it's necessary to have an
instance of Yb::Session class, which takes care of loading/saving the
objects, keeps track of changes, controls the relationships, etc. On creation
of Session pass a database scheme to it.

int main() {
    Yb::init_schema();  // gather all declarations in one schema
    Yb::Session session(Yb::theSchema(), "sqlite+sqlite://./tut1.db");

Create a new object of class Client, then fill out its attributes and
register it in Session. After all changes made it's necessary to apply all the
changes (method session.commit()). In this example there will be one
INSERT and then one transaction COMMIT. The primary key value in this
example is assigned on insertion.

    Client client;
    client.name = "Some Name";
    client.email = "some@email";
    client.dt = Yb::now();
    client.save(session);
    session.commit();
    return 0;
}

If you're using Unix you can compile and link as shown below. Here it's
assumed that variable YBORM_ROOT is set to point to the root of installation
of YB.ORM.

$ c++ -o tut1_new tut1_new.cpp -I ${YBORM_ROOT}/include/yb -L ${YBORM_ROOT}/lib -lybutil -lyborm

Try to launch the executable (it may require to set path to library location
for YB.ORM). If there is no database file tut1.db in the current directory,
then you will get error: "no such table".

$ export LD_LIBRARY_PATH=${YBORM_ROOT}/lib:${LD_LIBRARY_PATH}
$ ./tut1_new 
terminate called after throwing an instance of 'Yb::DBError' 
  what():  no such table: T_CLIENT 
Backtrace:
...

The Session object has the schema description and it can create tables in the
database, by sending DDL statements produced using proper SQL dialect. The
only method argument controls whether possible errors should be ignored (e.g.
if the table already exists).

session.create_schema(true);

Also, now Client class has got new static data member named "c", which
contains column metadata object Yb::Column for each attribute. This kind of
metadata is suitable to construct query expressions when querying for objects.
The following example issues a query with filter by field.

Client client = Yb::query<Client>(session).filter_by(
    Client::c.name == "Some Name").order_by(Client::c.dt).first();

There are quite a few advantages in placing OR-mapping declaration within
class declaration: no need to use external code generation tool, easier to
maintain custom methods in the class. When considering YB.ORM the other
alternative is to describe the mapping in form of XML-config and use a code
generation tool as shown in Tutorial1.


Related

Wiki: en_Tutorial1

Want the latest updates on software, tech news, and AI?
Get latest updates about software, tech news, and AI from SourceForge directly in your inbox once a month.