Перейти к основному содержанию
`Ctrl`+`K`

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

Документ описывает ключевые механизмы управления данными объектов в системе: времязависимые значения, копирование, группировку и денормализацию деревьев. Все функции доступны на уровне метаданных и поддерживают конфигурацию через 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`.