Управление данными объекта#

Документ описывает ключевые механизмы управления данными объектов в системе: времязависимые значения, копирование, группировку и денормализацию деревьев. Все функции доступны на уровне метаданных и поддерживают конфигурацию через ODM и пользовательский интерфейс.

Времязависимые значения#

Времязависимые атрибуты хранят разные значения для разных периодов времени. Реализовано через таблицу Btk_TimeDepValue, где каждая запись содержит значение атрибута для объекта на указанном периоде. Период ограничен датой начала (dBegin) и датой окончания (dEnd). Если дата не заполнена — это открытый период. Сам атрибут класса хранит только одно актуальное значение.

Примечание

Для каждой пары объекта и атрибута периоды не могут пересекаться.

Создание времязависимого значения#

Создать времязависимое значение можно:

  • Указав свойство isTimeDepValue у атрибута в ODM.

  • Включив настройку «Времязависимое значение» в интерфейсе.

Изменение времязависимых значений#

При вводе значения в поле времязависимого атрибута выполняется поиск существующих значений:

  • Если значений нет — создается запись без указания границ периода.

  • Если значения есть — пользователю предлагается изменить значение для текущего периода или добавить новое значение в новый период. При добавлении:

    • Новый период начинается с текущей даты.

    • Для предыдущего периода dEnd устанавливается как «текущая дата минус 1 день».

Редактор времязависимых значений#

Для времязависимых атрибутов рядом с полем отображается кнопка, открывающая специальный редактор. В редакторе три поля:

  • Дата начала.

  • Дата окончания.

  • Значение (обязательное).

Перед сохранением проверяется пересечение периодов. После закрытия редактора атрибуту присваивается значение, соответствующее текущей дате.

Использование в бизнес-логике#

Пример получения значений#

// Получение последовательности rop по объекту и атрибуту
Btk_TimeDepValueApi().getByObjectAndAttr("30151/146451".ng, 757.nl)

// Получение последовательности rop в отсортированном порядке
Btk_TimeDepValueApi().getByObjectAndAttrSorted("30151/146451".ng, 757.nl)

// Получение числового значения на текущую дату
Btk_TimeDepValueApi().findValueByCurrendDateByAttr("30151/146451".ng, 757.nl).asNNumber

// Получение строкового значения на определённую дату
Btk_TimeDepValueApi().getByObjectAndAttr("30151/146451".ng, 757.nl)
  .find(rop => rop.get(_.dBegin) < "04.04.2025".nd && rop.get(_.dEnd) > "04.04.2025".nd)
  .map(_.get(_.jValue))
  .getOrElse(NString())

Пример установки значения#

// Добавление значения на определённый диапазон
val rop = Btk_TimeDepValueApi().insertByAttr("30151/146451".ng, 757.nl, "01.01.2025".nd, "31.12.2025".nd)
Btk_TimeDepValueApi().setValue(rop, "15.10.2025".nd)

Копирование объектов#

При необходимости, для класса генерируется операция копирования. Метод позволяет создать новый объект, скопировав значения атрибутов и содержимое коллекций. Выполняется глубокое копирование — для коллекций создаются новые записи.

Также возможно добавить данные из одного объекта в другой.

Копирование управляется свойствами в метаданных (по умолчанию = true). Настройка возможна:

  • На уровне класса — включение/отключение копирования.

  • На уровне атрибута — исключение конкретных полей из копирования.

Уровни настройки#

  • На уровне класса: свойство isCopyObjectEnabled.

  • На уровне атрибута: свойство isCopyInCopyObject.

Если копирование включено для класса:

  • В мастер-выборке EntityAvi#Default создана операция «Копировать». По умолчанию пустая и неактивная. Для классов с isCopyObjectEnabled="true" операция активируется и содержит исполняемый код.

  • В отображении Card создается операция copyObjectCard, которая создаёт новый объект и копирует в него данные по CardRep.IdItemSharp. Параметр idBOParent# используется как мастер-объект.

Настройка в ODM#

Пример настройки класса:

<class xmlns="http://www.global-system.ru/xsd/global3-class-1.0"
       name="Mct_OperCard"
       caption="Справочник операционных карт"
       cardEditor.representation="Card"
       listEditor.representation="List"
       viewOptions.openCardType="mdi"
       supertype="reference"
       isCopyObjectEnabled="true"
       attachType="simple"/>

Пример настройки атрибута:

<attr name="sCreateUser"
      attribute-type="Varchar"
      type="basic"
      isCopyInCopyObject="false"/>

При генерации метода copyObject в мастер-классе автоматически добавляются вызовы copyObject из коллекций — если для их классов копирование включено.

Если свойство isCopyInCopyObject не указано — атрибут будет копироваться.

По умолчанию не копируются системные атрибуты:

  • id

  • gid

  • gidRef

  • sImpExpKey_dz

  • nImpExpFlag_dz

  • sMnemoCode_dz

  • sHeadLine_dz

  • Атрибуты связи с мастер-сущностью.

Параметры метода copyObject#

  • Для миксинов: (gidFrom: NGid, gidTo: NGid, gidParent: NGid)

  • Для V-коллекций: (idFrom: NLong, idTo: NLong, gidParent: NGid)

  • Для остальных: (idFrom: NLong, idTo: NLong, gidParent: NLong)

Метод copyObject создаёт объект (если gidTo/idTo не передан) через DPI-метод. Установка значений выполняется через DPI-сеттеры.

Группировка#

Группировка используется для:

  • Систематизации хранения объектов.

  • Удобства восприятия пользователем.

  • Массового управления характеристиками и настройками объектов.

Дерево групп — иерархическая структура, где потомки наследуют характеристики предков с возможностью переопределения.

Включение группировки#

Чтобы включить группировку для класса:

  1. Откройте ODM-файл класса.

  2. Укажите group.type — тип группировки:

    • single — объект может входить только в одну группу.

    • multi — объект может входить в несколько групп.

  3. Укажите group.root — системное имя корня группировки.

  4. Добавьте в набор коллекций класса развязку групп:

<class xmlns="http://www.global-system.ru/xsd/global3-class-1.0"
       name="Bs_Contras"
       caption="Контрагент"
       supertype="reference"
       cardEditor.representation="MainCard"
       listEditor.representation="MainRoList"
       roListEditor.representation="ROList"
       viewOptions.openCardType="mdi"
       group.type="multi"
       group.root="Group3" />
<var-collection name="Btk_ObjectGroup"
                ref.attr="gidSrcObject"/> 

Требования#

Для подключения группировки класс должен иметь глобальный идентификатор (gid).

Добавление закладки в карточку#

Для управления группами в карточке объекта можно добавить закладку:

  1. Откройте AVM-файл класса.

  2. Добавьте элемент:

<tabItems isVisible="true">
  <tabItem selection="gtk-ru.bitec.app.btk.Btk_ObjectGroupAvi"
           representation="List_Object"
           id="2"
           caption="Группы объекта"/>
</tabItems>

Реализация и использование#

  • Связь объекта с группой — через класс Btk_ObjectGroup.

  • Денормализованное дерево групп — в таблице Btk_FlatObjectGroup.

Эти таблицы можно использовать в запросах для фильтрации объектов или реализации прикладной логики.

Интеграция с выборкой#

При включении группировки в список объектов добавляются операции по работе с группами.

Чтобы открыть панель группировки:

  1. Откройте список объектов.

  2. Выполните операцию «Открыть группы» — слева появится панель с деревом групп.

После открытия:

  • В основной части отображаются объекты из текущей группы и её потомков.

  • Новые объекты создаются в выбранной группе.

Денормализация классов-деревьев#

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

Реализован трейт TreeDenormApi (ru.bitec.app.btk.denormalization.TreeDenormApi), предоставляющий функциональность:

  • Создание.

  • Обновление.

  • Удаление денормализации по объектам из класса-дерева.

Пример#

Пусть класс-дерево называется Btk_TreeExample.

Необходимо создать класс денормализации, например — Btk_TreeExampleDenormalization.

Обычно такой класс содержит атрибуты:

  • id

  • idClass

  • idParent

  • idChild

  • nParentLevel

Подключение трейта#

Подключите трейт TreeDenormApi к API класса денормализации и реализуйте абстрактный метод masterTableName, возвращающий имя таблицы класса-дерева:

class Btk_TreeExampleDenormalizationApi extends
  Btk_TreeExampleDenormalizationDpi[
    Btk_TreeExampleDenormalizationAro,
    Btk_TreeExampleDenormalizationApi, 
    Btk_TreeExampleDenormalizationAta
  ]
  with TreeDenormApi[
    EntityAbst, java.lang.Long,
    Btk_TreeExampleDenormalizationAro
  ] {
  
  override def masterTableName: NString = "Btk_TreeExample"
}

Переопределение имён полей#

Если имена полей отличаются от стандартных, переопределите методы:

def idParentFieldName = "idParent"
def idChildFieldName = "idChild"
def nParentLevelFieldName = "nParentLevel"

Обновление денормализации#

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

  • В методе установки ссылки на предка (например, setidParent).

  • В методе insert — на случай, если родительская запись изначально пуста.

Вызовите метод:

ru.bitec.app.btk.denormalization.TreeDenormApi#updateDenormAfterFlush

Метод накапливает все переданные записи и обновляет денормализацию после сброса данных в БД.

Удаление денормализации#

Удаляйте денормализацию при удалении записи из основного класса — обычно в методе delete. Вызовите:

ru.bitec.app.btk.denormalization.TreeDenormApi#deleteDenormBeforeFlush

Метод накапливает записи и удаляет денормализацию перед сохранением в БД.

Прямое обновление (не рекомендуется)#

Возможно обновление/удаление непосредственно при редактировании, но это замедляет работу системы.

Используйте только при крайней необходимости:

ru.bitec.app.btk.denormalization.TreeDenormApi#updateDenorm
ru.bitec.app.btk.denormalization.TreeDenormApi#deleteByObject

Примечание

Пример реализации см. в Bs_DepartmentTreeApi в связке с Bs_DepartmentApi.