Класс#

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

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

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

  • Доменная автономная бизнес логика(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 запрос, на запрос мастер объекта, 1 запрос на запрос коллекций 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 миксин – это специализированный класс, каждый объект (запись в таблице) которого соответствует одному объекту подключенного класса (записи в таблице). Mixin-класс может иметь не ограниченное число подключенных классов. Первичным ключом для mixin-объектов является поле gidRef. Значение поля gidRef равно значению поля gid объекта подключенного класса и заполняется в момент создания объектов.

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

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

Примечание

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

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

getByGid(gidpRef: NGid): Option[ApiRop]

Создание 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

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

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

При формировании кода для классов с supertype="document" и supertype="reference", этот миксин автоматически подключается к классу. Допускается отключение миксина Btk_Object путём указания свойства в Odm файле:

<reflection isEnabled="false"/>

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

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

Для атрибутов, ссылочных на миксин, необходимо указывать тип 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>