Создание проекта хранилища Udb

  !   Данная информация предназначена только только для IT-специалистов по системной интеграции модулей БИОСОФТ-М. (см. Руководства пользователя к программным продуктам)

На примере проекта Costo - cетевое хранилище Bijou для регистрации компонентов.

Перед внедрением данного алгоритма к себе в большой проект следует разобраться в общем принципе интерфейса с Udb изучив Простой пример использования Udb.

Подключение Udb к проекту

1) В главный хидер проекта включить UdbBasedProject.h в такой форме:

// CCostoProject.h
 
// Core System Libraries
#include <opp/Univ/Islib/Include/Islib.h>
#include "opp/Univ/Islib/Include/IslibStaticLibLink.h"
 
//VL: 2013-09-12
// Udb Support
#include "opp/app/VL/uni/Datrans/Packages/Udb/iface/UdbBasedProject.h"
//VL.

Это не только вставит все нужные темплейты но и переведет компиляцию всего проекта в особые режимы контроля и трансформации кода необходимые для Udb. Некоторые легаси фичи в таком проекте могут уже не компилироваться.

2) Загружаем модуль с базовым набором функций (для сетевого режима понадобятся дополнительные модули Biointa):

    x_rCostoParaLoader->TryInitAsCostoParaServiceProcess();
    if (!x_rCostoParaLoader->IsStartedAsCostoParaService())
    {
        // Dependencies only for main non-ParaService app
        CModule::GPreloadCommonDll("Datrans");
    }

3) Для базового набора функциональности Udb добавлять что либо в Jamfile.jam не требуется (для сетевого режима и универсального бровзера Ubro могут потребоваться).

Пакет Store

Если хранилище это единственная функция проекта то можно было бы совместить это с Session. Но у Session есть свои традиционные роли которые не следует замешивать в один класс с нижеописанным инкапсулятором Udb.

Инкапсулировать драйвер Udb хранилища

В Impl хранилища будем хранить соединение с БД. Можно сделать его приватным. Но бывает так что другим классам хранилища нужно получать из него полезные вещи и он становится проперти в StoreImpl.

class C...StoreImpl : public C...StoreIface
{
public:
 
// Attributes
 
    // UdbConnection
    ref<CUdbConnectionIfaceGp> x_r...UdbConnection,
            auto(Get);

Второй объект, который всегда необходим для управления БД это корневая запись. Он должен быть приватным, либо Get-only пропертей, которая понадобится для запроса объектов непосредственно присоединенных к корню.

    ref<CDb...Root> x_rDb...Root,
            auto(Get);
Добавить как минимум корневой CDb класс

И объявляем CDb класс для корневой записи. Создаем все CDb классы в папке Store/impl/db:

//
// CDb...Root -
//
//   Root singleton db record
//
 
class CDb...Root : public dbobject
{
......
};

В этот момент уже должно компилироваться, но БД еще не используется.

Открыть БД

Инициализация БД состоит из трех шагов

  • создание списка таблиц
  • открытие соединенения
  • сохранение ссылки на корневую запись

Пока добавляем только декларированную выше корневую таблицу:

    ref<CUdbConnectionIfaceGp> rUdbConnection =
        m_/x_r...UdbConnection;
 
    // init our database structure
    rUdbConnection->
        DeclareUdbTableClass(
            ref<CDb...Root>());

Открываем соединение с указанием драйвера (локальный/сетевой) и пути к локальной БД (кешу):

    // Open DB
    str sError;
    rUdbConnection->
        OpenUdbConnection(
            type<CUdbStorageTypeIfaceGp>()->
                AsUdbStorageTypeFor.............(),
            pathDb,
            out sError);
 
    HandleDbError(sError);

Для запросов нам понадобится корневой контейнер который мы инициализируем и сохраняем ссылку:

    _m/this->x_rDb...Root =
        dbref<CDb...Root>().
            InitRoot(
                rUdbConnection);
Централизованная обработка ошибок

Обработку ошибок сразу инкапсулируем в своей HandleDbError():

void C...StoreImpl::HandleDbError(
        str sError)
{
    if (sError == "")
    {
        return;
    }
 
    rFAIL(sError);
 
    type<C...LogTypeIface>()->
        As...LogTypeForDbErrors()->
            Log...Event(
                Enru_(
                    <Cannot access app data...>),
                sError);
}
Закрыть БД

Обязательно нужно закрывать соединение при нефатальном завершении приложения. Эта операция обеспечивает целостность данных способом, зависящим от реализации драйвера Udb.

void C...StoreImpl::OnClose...Store()
{
    if (_m_b...StoreOpened)
    {
        _m_b...StoreOpened = false;
 
        // Write DB
        x_rRelaUdbConnection->
            FlushUdbConnection();
    }
}

После этого проект будет создавать пустую БД (или соединятся с ней по сети) и выдавать ошибки в случае сбоев инициализации.

Дальше

Для того чтобы проект начал делать что то полезное нужно создать CDb классы хранящие прикладные данные, логически присоединенные к контейнеру CDb...Root и реализовать добавление и запросы к данным. См. статьи по Udb.