Skip to content
Viacheslav Naydenov edited this page Oct 22, 2014 · 1 revision

Описание ОР-проекции в коде доменного класса

В этом примере предполагается использование встроенной СУБД Sqlite3, для других СУБД поменяется лишь строка подключения в объекте Yb::Session. Предположим, что в БД имеется таблица client_tbl, в которой есть суррогатный первичный ключ и несколько информационных полей (имя, e-mail и т.д.).

Можно создать класс C++, который будет соответствовать этой таблице, а его экземпляры — отдельным записям в ней. При объявлении класса нужно унаследовать его от Yb::DomainObject. Описание проекции задается с помощью макроса YB_DECLARE и нескольких вспомогательных макросов, которые формируют описание отдельных атрибутов.

Макросы YB_COL_* задают атрибуты указывая для них такие параметры как имя свойства класса, имя поля в таблице, тип, размер поля и пр. Отличаются они количеством позиционных параметров, YB_COL — наиболее общий из таких макросов, принимает наибольшее количество.

#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; } 
}; 

Эта описание класса можно поместить как в .cpp файле, так и в заголовочном файле. Еще один вызов макроса нужно поместить в один из ваших .cpp файлов:

YB_DEFINE(Client)

Класс Client автоматически дополнен несколькими новыми членами данных и методами. В том числе, у объектов данного класса появились свойства (id, dt, name, …), через которые можно получить доступ к значениям атрибутов как на чтение, так и на запись, а также проверять атрибуты на пустоту (IS NULL).

Чтобы использовать экземпляры этого класса понадобится вспомогательный объект Сессии (класс Yb::Session), который возьмет на себя вопросы загрузки/сохранения объектов, отслеживания изменений, управления связями и пр. При создании Сессии ей нужно передать актуальную схему ОР-проекции.

int main() {
    Yb::init_schema();  // собрать все декларации в одну схему
    Yb::Session session(Yb::theSchema(), "sqlite+sqlite://./tut1.db");

Для вставки нового объекта в таблицу создается новый экземпляр класса Client, заполняются его атрибуты, он передается в ведение Сессии. В конце происходит применение всех накопленных изменений (метод session.commit()), в нашем случае — вставка новой записи в таблицу T_CLIENT и последующая операция COMMIT. Первичный ключ в данном примере получает значение автоматически в момент синхронизации нового объекта с БД.

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

Скомпилировать пример при использовании Unix можно приведенной ниже командной строкой. Предполагается, что переменная YBORM_ROOT указывает на корень установки YB.ORM.

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

Если запустить (для запуска может понадобиться прописать путь до библиотек YB.ORM) полученный исполняемый файл без файла базы данных tut1.db в текущем каталоге, то будет получена ошибка "таблица не существует".

$ 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:
... 

Если требуется, объект Сессия может воссоздать таблицы по описанию схемы, выполнив соответствующие DDL операторы для заданного соединения с использованием текущего диалекта SQL. Параметр функции указывает игнорировать ли ошибки при выполнении DDL операторов, например, если схема существует.

session.create_schema(true);

У класса Client добавлен статический член данных с именем "c", в котором для каждого атрибута имеются его метаданные в виде объекта Yb::Column. Эти метаданные удобно использовать для составления выражений запросов при выборке объектов. Вот как можно найти объект по значению поля:

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

Преимущества встроенного описания ОР-проекции очевидны: не требуется запуск утилиты генерации кода, легче поддерживать дополнительные методы в классе. При использовании YB.ORM альтернативой описанию ОР-проекции внутри декларации класса является генерация доменных классов по описанию схемы в XML специальной утилитой, как это описано в Tutorial1.

Clone this wiki locally