-
Notifications
You must be signed in to change notification settings - Fork 20
ru_TutorialDecl
В этом примере предполагается использование встроенной СУБД 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.