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

# Класс

Определяет правила хранения и обработки таблицы базы данных.

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

Перечень генерируемых элементов:

- Доменная автономная бизнес логика(`Dpi`)
  Содержит код для автономной бизнес логики

- Каркас прикладной автономной логики(`Api`)
  `scala` класс с окончанием `Api`, в котором пишется автономная бизнес логика для работы с классом. Наследуется от `Dpi`

- Доменная интерактивная бизнес логика(`Dvi`)

- Каркас прикладной интерактивной логики(`Avi`)
  `scala` класс с окончанием `Avi`, в котором пишется интерактивная бизнес логика. Наследуется от `Dvi`

- Доменная разметка выборки(`dvm.xml`)
  Содержит сгенерированную по умолчанию разметку выборки.

- Каркас прикладной декларации пользовательского интерфейса(`Avm`)
  `xml` файл с расширением `avm.xml`, в котором пишется разметка выборки

- Интеграция с `Orm`

  - `Pojo` объект для хранения данных в кэше

  - `Aro` объект интеграции pojo в фреймворк

Примечание

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

- `D` - Domain
  Доменный элемент всегда перезаписывается при кодо-генерации и содержит бизнес логику для подключения сервисов.

- `A` - Application
  Прикладной элемент не изменяется при кодо-генерации и служит для хранения бизнес логики написанной программистом вручную. Прикладной элемент наследуется от доменного элемента.

Доступные прикладные сервисы:

- Аудит
  Аудит предназначен для фиксации различных событий при работе пользователей в системе

- Администрирование
  Позволяет управлять доступом к автономной и интерактивной бизнес логике за счет выдачи прав на привилегии.

- Универсальная фильтрация
  Позволяет пользователю строить комплексную фильтрацию списка классов на уровне базы данных. В универсальном фильтре можно использовать как поля самого класса и его коллекций так и поля классов на которые есть ссылки.

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

- Копирование объектов
  Кодогенерация бизнес логики для копирования объектов

- Группировка
  Группировка используется для систематизации хранения объектов и удобства восприятия пользователем, так же группировка позволяет массово управлять характеристиками и настройками объектов класса.

- Сервис прикрепленных файлов
  Позволяет прикреплять к объектам класса произвольные файлы

- Поиск по шаблону
  Возможность поиска объектов класса по частичному или полному совпадению введенного текса со значениями полей объекта или его заголовка и мнемокода

- Объектные характеристики
  Возможность добавлять произвольные поля в класс на проекте

- Генерация штрих-кодов объекта
  Механизм генерации штрих кодов объектам класса при создании

- Подписи объектов для печати
  Используется при печати отчетов. Позволяет формировать в печатной форме список лиц с местом для подписи

- Полнотекстовый поиск
  Возможность класса осуществлять быстрый поиск по значению атрибутов класса

## Схема окружения

Окружение класса создается в момент кода генерации:

## Общие сведения о классах

Класс сущности(далее просто класс) определяет хранилище совокупности объектов(строк), имеющих одинаковые характеристики, подчиняющихся общим настройкам и операциям, функционирующих в рамках единой логики.

Класс содержит набор атрибутов, атрибут может быть:

- Простым значением
  Используется для ввода и хранения значения определенного типа данных

- Ссылочным
  Используется для выбора значения атрибута из справочника или другого множества

- Переменной ссылочности
  Используется для ссылочности на любую таблицу в системе

- Ссылочным на класс
  Таблица классов является служебной таблицей мета данных хранящей весь перечень классов в решении.

Класс должен иметь уникальное системное имя и наименование.

Правила наименования класса:

- Системное имя должно задаваться на латинице

- Имя должно быть в формате `{Module}_{Name}` где:

  - `Module` - Имя модуля

  - `Name` - Имя класса
    Имя класса должно быть в единственном числе, именительном падеже

Пример:

- `Lbr_Book`

## Типы данных

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

Основные типы данных, используемые для атрибутов класса:

- Целое число

- Дробное число

- Строка

- Дата

- Ссылка (на объект заданного класса)

- Ссылка на класс

- Переменная ссылка (на объект произвольного класса)

- Глобальный идентификатор gid

- Json контейнер

### Простые типы

Простыми типами являются: Число, строка, дата

Тип | postgresql | odm | Рекомендация по использованию
--- | --- | --- | ---
Строка фиксированной длинны | varchar | Varchar | Текст до 4000 символов
Строка переменной длинны | text | Text | Текст до 15 мегабайт
Число | number | Number | Целое или дробное число
Дата | date | Date | Дата, дата и время

### Ссылочные типы

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

#### Ссылка и переменная ссылка

Ссылка на объект и переменная ссылка используются для организации ссылочности объектов одного класса на объекты другого класса (или объекты своего собственного класса).

Тип `ссылка` может хранить объекты одного класса, который задан в настройках.

Тип `переменная ссылка` хранит ссылку на объект любого класса.

#### Ссылка на класс

Хранит ссылку на класс. Обычно используется совместно с типом `переменная ссылка` для хранения класса, объект которого содержится в переменной ссылке.

#### Глобальный идентификатор gid

Gid является уникальным идентификатором в рамках системы. Переменная ссылка на gid является альтернативой системе переменной ссылочности из двух атрибутов (ссылка на класс + переменная ссылка на объект). Для организации переменной ссылки через gid используется один атрибут.

##### Формат ссылки gid

Глобальный идентификатор состоит из строки:

    gid :== idClass \ id[@ idNode]

Где:

- idClass – идентификатор класса
  Ссылка на объект в таблице btk_class

- id – идентификатор

- idNode – идентификатор удаленного нода
  В текущей базе, задается для объекта созданного на удаленном узле (если используется механизм репликации на уровне системы)

### Json контейнер

Json контейнер – это расширение объекта класса NoSQL нотацией в реляционной СУБД. Контейнер не имеет жесткой, заранее определенной схемы и основан на множестве пар «ключ‑значение». Это позволяет использовать его как динамическое расширение объекта. Для добавления новых данных в контейнер не требуется перекомпиляция кода или изменение структуры СУБД.

## Супертипы классов

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

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

Основные супертипы:

- `reference` - Справочник
  Справочник — это прикладной объект, который позволяет хранить данные, имеющие одинаковую структуру и списочный характер. Пример: Справочник физ. Лиц; Места хранения; справочник ТМЦ.

- `document` - Документ
  Документ – это прикладной объект, который хранит данные о событиях или операциях на предприятии. Пример: Заявка на отгрузку; Приходная накладная; Акт сверки. Документ обычно имеет атрибут состояние, который отражает его жизненный цикл.

- `collection` - Коллекция
  Коллекции представляют собой классы, объекты которых не имеют права на самостоятельное существование и могут быть созданы только для объектов других классов. Коллекции применяются в качестве табличных частей документов или логических развязок между классами. Добавление коллекций в бизнес объект позволяет массово загружать данные в объектный кэш, что минимизирует нагрузку на базу данных. Так же возможно обход элементов коллекции по родителю без транзакционного индекса, что уменьшает нагрузку на процессор.

- `vcollection` – Переменная коллекция
  Переменная коллекция расширяет возможности обычных коллекций и может ссылаться на родителя переменной ссылкой. Это требуется, когда для нескольких классов используется одинаковая коллекция.

- `journal` - Журнал
  Журнал – это особый тип классов, приспособленный для хранения большого количества записей. Такие классы имеют ограниченную функциональную обвязку ядровыми методами фреймворка. Это позволяет увеличить быстродействие при работе с журналом. Примеры: записи по потребности ТМЦ на заказ в разрезе документов; журнал трудоемкости в разрезе операций и т.д.

- `trait` – Трейт
  Абстрактный класс-предок, не имеющий собственной структуры хранения. Такой класс содержит общую логику нескольких классов-потомков и является частью механизма повторного использования кода.

- `mixin` – Миксин (класс-примесь)
  Миксин – это особый вид классов, которые служат для хранения данных из разных классов. Используются для построения общих списочных форм различных диалогов подбора в пользовательских интерфейсах, а также для удобства обработки данных в прикладной бизнес-логике. Миксин позволяет объединить несколько разных таблиц вместе что дает возможность использовать внешние ключи и индексы на данное объединение.

## Бизнес-объект

Бизнес-объект (БО) - объединение нескольких классов и их коллекций в группу для более удобного манипулирования ими при работе с кэшем и конфигурировании вспомогательных сервисов.

Бизнес объект позволяет:

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

- Настраивать права доступа
  По бизнес объекту создается административный объект на котором можно массово выдать привилегии для всех классов бизнес объекта

- Управлять электронной подписью
  Можно настроить правила подписи всего бизнес объекта включая не только шапку, но и все вложенные коллекции.

- Настраивать интеграцию и репликацию

### Навигация по бизнес-объекту

Навигацией является последовательное посещение элементов бизнес-объекта сверху вниз. При навигации перемещение между объектами идет по кэшу, при этом обеспечивается автоматическая дозагрузка объектов в кэш по необходимости.

В процессе навигации объекты не блокируются и могут при необходимости быть вытолкнуты из кэша, что вызовет автоматическую дозагрузку (обновление).

Примеры навигации:

    val empApi = EmployeeApi()
    empApi.load(7452) :/ { id =>
      println(id.id)
      for(idDes <- AddressApi.byParent(id)){
        println(s"address: city=${ idDes.get(_.city)}")
      }
    }

## Навигация в рабочем пространстве

Объекты загружаются из базы или из кросс-сессионного кэша, при загрузке происходит пессимистическая либо оптимистическая блокировка. Объекты находятся в рабочем пространстве до момента коммита. В момент коммита рабочее пространство очищается.

При навигации можно производить модификацию объектов. Api гарантирует корректную навигацию по мастер деталям без необходимости flush и clean кэша или немедленной загрузки коллекций.

## Массовая загрузка объектов.

При массовой загрузке объектов происходит минимизация обращений к базе данных. При обходе в обычном режиме 3-х уровневого бизнес-объекта произойдет n+2 запросов, где n количество деталей 2-го уровня, 1 запрос, на запрос мастер объекта, 2 запрос на запрос коллекций 2-го уровня. Однако если объект запросить с помощью массового запроса, то при его обходе произойдет всего 3 запроса. Что может ускорить навигацию по объектам более чем в 10 раз.

Пример массового запроса:

    for (rv <- new OQuery(Stk_WarrantAta.Type){
      where (t.id in idap)
      batchAll()
    }){}

Примечание

Объектные запросы активно расходуют оперативную память. Это накладывает ограничение на использование их в процедурах бизнес-логики. Обычно объектные запросы используются для организации пользовательского интерфейса (редактирование одного объекта с коллекциями, справочники, документы и т.д.), а для программирования внутренних процедур бизнес-логики используются SQL запросы в БД.

## Работа c провайдерами строк

Провайдер строки - Rop используется для работы со строкой данных (Aro), загруженных в рабочее пространство, обеспечивая гарантию того, что при доступе к строке данная строка будет находиться в рабочем пространстве.

Метод получения rop:

    thisApi().load(идентификатор.asNLong)

Примеры сеттеров в файле выборки:

    val rop = thisRop
    thisApi().setidContras(rop,getVar("super$id").asNLong)

Работа с rop в API:

    for (ropGrade <- new OQuery(entityAta.Type){
      where (t.idGdsGrade === idpGdsGrade)
    }) {
      setidGdsGrade(ropGrade, None.nl)
    }

Работа с AnyRop(rop неизвестного типа):

    anyRop match {
      case Btk_GroupApi(ropGroup) =>
        ropGroup.get(_.sCaption)
      case Btk_ClassApi(ropClass) =>
        ropClass.get(_.sName)
      case _ => throw AppException("Ожидали роп группы или класса")
    }

    // получить из списка только ропы определенного класса
    ropaAny
      .collect {
        case Btk_GroupApi(ropGroup) => ropGroup
      }

## Оптимистическая блокировка

Так как система Global Postgres ориентирована на работу с короткими транзакциями, фреймворк по умолчанию включает для классов оптимистическую блокировку.

Принцип работы оптимистической блокировки:

- При загрузке строки в кэш, запоминается версия изменения.

- Если строка изменяется, увеличивается версия изменения.

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

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

    <class useOptimisticLocking="false"/>

Примечание

Для хранения версии изменений используется служебное поле `nVersion_dz`

## Коллекции

Коллекцией является сущность, объекты которой не могут существовать без ссылки на объект-владелец. Классы коллекций объявляются в Odm сущности-владельце.

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

Связывание сущностей владельца и коллекции производится путём объявления элемента `collection` в секции `collections`.

    <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
    <class xmlns="http://www.global-system.ru/xsd/global3-class-1.0"
          name="Bs_Brigade" caption="Бригада"
          cardEditor.representation="Card"
          listEditor.representation="List"
          viewOptions.openCardType="mdi"
          supertype="reference">
    	<attributes>
    		<attr name="id"
              attribute-type="Long"
              caption="Идентификатор"
              order="-1"
              type="basic"
              isVisible="false"/>
    		<attr name="idClass"
              attribute-type="Long"
              caption="idClass"
              order="-2"
              type="basic"
              isVisible="false"/>
    		<attr name="gid"
              attribute-type="Varchar"
              isVisible="false"/>
    		<attr name="sCode"
              attribute-type="Varchar"
              caption="Код"
              order="10"
              isMnemoCode="true"
              type="basic"
              isVisible="true">
    			<autonum id="1">
    				<dimension name="Dim1"/>
    			</autonum>
    		</attr>
    		<attr name="sCaption"
              attribute-type="Varchar"
              caption="Наименование"
              order="20"
              isHeadLine="true"
              type="basic"
              isVisible="true"/>
    		<attr name="idDepartment"
              attribute-type="Long"
              caption="Подразделение"
              order="30"
              type="refObject"
              ref.class="Bs_Department"/>
    		<attr name="idForeman"
              attribute-type="Long"
              caption="Бригадир"
              order="40"
              type="refObject"
              ref.class="Bs_Employee"/>
    		<attr name="idMaster"
              attribute-type="Long"
              caption="Мастер"
              order="50"
              type="refObject"
              ref.class="Bs_Employee"/>
    	</attributes>
    	<collections>
    		<collection name="Bs_BrigadeStaff"
                    ref.attr="idBrigade"
                    cascadeOnDelete="true"/>
    	</collections>
    	<dbData>
    		<script name="dataInstall" version="1">
    			<install>Bs_BrigadeApi.dataInstall()</install>
    		</script>
    	</dbData>
    </class>

Для класса коллекции указывается супертип «collection», это гарантирует наследование scala-классов от необходимых системных классов.

    <?xml version="1.0" encoding="UTF-8" standalone="yes"?>

    <class xmlns="http://www.global-system.ru/xsd/global3-class-1.0"
           name="Bs_BrigadeStaff"
           caption="Состав бригады"
           cardEditor.representation="Card"
           listEditor.representation="List"
           viewOptions.openCardType="mdi"
           supertype="collection">
    	<attributes>
    		<attr name="id"
    		      attribute-type="Long"
    		      caption="Идентификатор"
    		      order="-1"
    		      type="basic"
    		      isVisible="false"/>
    		<attr name="idClass"
    		      attribute-type="Long"
    		      caption="idClass"
    		      order="-2"
    		      type="basic"
    		      isVisible="false"/>
    		<attr name="gid"
    		      attribute-type="Varchar"
    		      isVisible="false"/>
    		<attr name="idEmployee"
    		      attribute-type="Long"
    		      caption="Сотрудник"
    		      order="10"
    		      type="refObject"
    		      ref.class="Bs_Employee"
    		      isMnemoCode="true"/>
    		<attr name="idBrigade"
    		      attribute-type="Long"
    		      caption="Бригада"
    		      order="20"
    		      type="refObject"
    		      ref.class="Bs_Brigade"
    		      genListCollectionRep="true"/>
    		<attr name="dStart"
    		      attribute-type="Date"
    		      caption="Дата начала"
    		      order="30"
    		      type="basic"
    		      editorType="datePick"/>
    		<attr name="dEnd"
    		      attribute-type="Date"
    		      caption="Дата окончания"
    		      order="40"
    		      type="basic"
    		      editorType="datePick"/>
    		<attr name="bisForeman"
    		      attribute-type="Number"
    		      caption="Является бригадиром"
    		      order="50"
    		      type="basic"
    		      editorType="check"/>
    	</attributes>
    </class>

### Формирование кода

При формировании кода сущности-владельца производится пересоздание кода всех коллекций. Dpi коллекции будет унаследован от ChildApi.

    trait Xxx_XxxxDpi[T] extends ChildApi[java.lang.Long, ARO, API]

`Dvi` будет унаследован от `CollectionAvi`.

    trait Xxx_XxxxDvi extends CollectionAvi

Основные методы для работы:

    //создание по владельцу, возвращает rop созданного объекта
    Api().insertByParent(ropMaster)
    //загрузка всей коллекции по владельцу, возвращает обходчик записей отфильтрованных по rop предка
    Api().byParent(ropMaster)
    Api().byParent(idMaster)
    //удаление по rop объекта
    Api().delete(rop)

### Отображения-детали

Для формирования отображений выборки, данные которых ограничены по значению ссылочного поля, необходимо в odm-файле, для соответствующего ссылочного атрибута указать свойство genListCollectionRep=»true». Будет сформировано отображение List_{attr}.

    <attr name="idBrigade"
          attribute-type="Long"
          caption="Бригада"
          order="20"
          type="refObject"
          ref.class="Bs_Brigade"
          genListCollectionRep="true"/>

### Переменная ссылочность

Часто при проектировании бизнес-логики необходимо хранить в атрибуте коллекции ссылки на объекты нескольких классов. В этом случае необходимо хранить не только идентификатор ссылочного объекта, но и идентификатор ссылочного класса.

Для реализации переменной ссылочности, в Оdm коллекции необходимо создать атрибут, способный ссылаться на поле «gid» мастер-объекта.

    <attr name="gidSrcXxxxxx"
          attribute-type="String"
          type="refAnyObject"
          genListCollectionRep="true"/>

Примечание

У классов, на объекты которых может ссылаться коллекция с переменной ссылочностью обязательно должен существовать атрибут «gid». Рекомендуется индексировать данное поле.

### Каскадное удаление

Если у коллекции включено свойство «Каскадное удаление» (по умолчанию включено),

    <collections>
      <collection cascadeOnDelete="true"
                  name="Bs_PersonIdentityDoc"
                  ref.attr="idPerson"/>
      <collection cascadeOnDelete="true"
                  name="Bs_PersonProf"
                  ref.attr="idPerson"/>
    </collections>

то в dpi мастера формируется вызов метода delete из коллекций.

Для подключенных `vcollection` (переменных коллекций) код удаления необходимо писать вручную в api:

    override def delete(rop: ApiRop): Unit = {
      for (crop <- Bs_BankAccApi().byParent(rop)) {
        Bs_BankAccApi().delete(crop)
      }
      for (crop <- Bs_DefSettlerAddressApi().byParent(rop)) {
        Bs_DefSettlerAddressApi().delete(crop)
      }
      for (crop <- Bs_SettlerAddressApi().byParent(rop)) {
        Bs_SettlerAddressApi().delete(crop)
      }
      super.delete(rop)
    }

## Механизмы наследования

Во фреймворке нет полноценного классического наследования классов сущностей. Понятие «наследование» используется в качестве описания логической связи двух классов.

Вместо классического наследования фреймворк использует миксины и трейты.

### Миксин (Mixin)

Примесь (англ. Mix-in) — элемент языка программирования (обычно класс или модуль), реализующий какое-либо чётко выделенное поведение. Используется для уточнения поведения других классов и не предназначен для самостоятельного создания объектов.

В системе Global3 Postgres миксин — это специализированный класс, каждый объект (запись в таблице) которого соответствует одному объекту подключенного класса (записи в основной таблице). Миксин-класс может быть подключен к неограниченному числу других классов.
Для объектов миксина первичным ключом является поле `gidRef`. Его значение автоматически устанавливается равным значению поля `gid` объекта подключенного класса в момент создания.

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

Миксин может содержать произвольное число атрибутов. Если имя атрибута миксина совпадает с именем атрибута подключенного класса (или его наследника), значение будет синхронизировано автоматически.

Примечание

Все scala-классы, соответствующие миксину наследуются от системных классов D-ветви (имеют префикс «D»). Остальные scala-классы, соответствующие обычным сущностям, наследуются от системных классов S-ветви (имеют префикс «S»)

Для миксинов метод получения rop по `gidRef` называется `loadByGid`, а также реализован метод аналогичный методу get для SApi

    getByGid(gidpRef: NGid): Option[ApiRop]

#### Системные миксины

Функционально не отличаются от прикладных. Основной системный миксин — `Btk_Object`.

При формировании кода для классов с `supertype="document"` и `supertype="reference"`, этот миксин автоматически подключается к классу.
Именно этот миксин обеспечивает базовую инфраструктурную функциональность: корректную работу версионирования, аудита изменений и синхронизации данных.

Допускается отключение миксина Btk_Object путём указания свойства в Odm файле:

    <reflection isEnabled="false"/>

Пример смотрите в классе `Btk_Group`

#### Прикладные миксины

Все остальные миксины (например, `bs_settler`) создаются разработчиками вручную для решения конкретных прикладных задач и не являются частью системной функциональности.

#### Создание mixin-класса

В Odm файле необходимо объявить атрибут `gidRef`.

    <attr name="gidRef" attribute-type="Varchar"/>

У класса указать свойство «supertype=”mixin”».

    <class xmlns="http://www.global-system.ru/xsd/global3-class-1.0"
          name="Xxx_ClassName" supertype="mixin"/>

#### Формирование кода

При формировании кода для mixin-класса, Dpi будет унаследован от `MixinApi`.

    trait Xxx_XxxxDpi[T] extends MixinApi[java.lang.Long, ARO, API]

Dvi будет унаследован от `AppMixinAvi`.

    trait Xxx_XxxDvi extends AppMixinAvi

Основные методы для работы:

    //создание по rop мастера, возвращает rop миксина
    Api().insertByParent(ropMaster)
    //загрузка миксина по gidRef, возвращает rop миксина
    Api().loadByGid(gidRef)
    //удаления по gidRef
    Api().deleteByKey(gidRef)

#### Объявление подключенных классов (классов-наследников)

Для связывания класса с миксином необходимо в Odm файле указать имена классов-миксинов.

    <mixins>
      <mixin name="Bs_Settler" isDpiManaged="true"/>
    </mixins>

При формировании кода сущности в Dpi будет добавлен код:

- Вставки миксин-объекта в методе `insert`

- Удаления миксин-объекта в методе `delete`

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

При необходимости управления генерацией миксина вручную необходимо отключить формирование кода в Dpi с помощью настройки `isDpiManaged`.

По умолчанию по всем подключённым миксинам генерируется код в Dpi

#### Ссылочность на миксин

Для атрибутов, ссылочных на миксин, необходимо указывать тип `refAnyObject`:

    <attr name="gidSettler"
          attribute-type="Varchar"
          caption="Контрагент"
          type="refAnyObject"
          isVisible="false"
          order="20"
          ref.class="Bs_Settler"/>

Для возможности автоматической генерации HL и MC атрибутов, сеттеров этих атрибутов и добавления их в `selectStatement` и `onRefreshExt` необходимо указать в настройке `ref.class` класс миксина для ссылки.

Важно

Для миксинов по ссылочным атрибутам не генерируются внешние ключи. Вместо этого генерируются индексы.

### Трейт (Trait)

`Trait` — это механизм обеспечения повторного использования кода между классами. В отличии от наследования, класс может содержать несколько трейтов. Трейт не имеет объектов, собственной структуры хранения данных и визуального представления.

Создание трейта:

1. Создайте Оdm файл

2. укажите свойство `supertype="trait"`

При формировании кода будут созданы только Dpi и Api файлы. Dpi будет содержать только объявления сеттеров и геттеров.

#### Наследование сущности от трейта

Для наследования сущности от трейта, добавьте в Odm свойство класса `with="Trait_Name"`

Сущность, наследуемая от трейта, должна иметь все атрибуты, объявленные в трейте.

#### Перекрытие и порядок вызовов методов

Рассмотрим код трейта и наследуемого от него класса:

    trait Gs3_TraitApi[T] extends Gs3_TraitDpi[T] {
      override def setFNumber(rop: ApiRop, value: NNumber): Unit = {
        Logger.Factory.get(getClass).info("Gs3_TraitApi.setFNumber")
        super.setFNumber(rop, value)
      }
    }

    class Gs3_DescendantApi extends Gs3_DescendantDpi[T] with Gs3_TraitApi[T] {
      override def setFNumber(rop: ApiRop, value: NNumber): Unit = {
        Logger.Factory.get(getClass).info("Gs3_DescendantApi.setFNumber")
        super.setFNumber(rop, value)
      }
    }

В результате выполнения метода `Gs3_DescendantApi.setFNumber()` последовательность вызовов будет следующей:

1. `Gs3_DescendantApi.setFNumber`

2. `Gs3_TraitApi.setFNumber`

3. `Gs3_DescendantDpi.setFNumber`

## Пример разметки класса

    <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
    <class xmlns="http://www.global-system.ru/xsd/global3-class-1.0" name="Bs_GdsCostDeviationType"
           caption="Виды отклонений в стоимости ТМЦ"
           cardEditor.representation="Card" listEditor.representation="List"
           viewOptions.openCardType="mdi" supertype="reference">
        <attributes>
            <attr name="id" attribute-type="Long" caption="Идентификатор" order="-1" type="basic" isVisible="false"/>
            <attr name="idClass" attribute-type="Long" caption="idClass" order="-2" type="basic" isVisible="false"/>
            <attr name="gid" attribute-type="Varchar" isVisible="false"/>
            <attr name="sCode" attribute-type="Varchar" caption="Код" order="10" isMnemoCode="true" type="basic"
                  isRequired="true" isVisible="true"/>
            <attr name="sCaption" attribute-type="Varchar" caption="Наименование" order="20" isHeadLine="true" type="basic"
                  isRequired="true" isVisible="true"/>
            <attr name="sDescription" attribute-type="Varchar" caption="Описание" order="30" type="basic" editorType="memo"
                  isVisible="true">
                <descriptionColumn/>
            </attr>
        </attributes>
    </class>