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.