Модель. Связи
Модель может быть связана с другими моделями:
через свойство. Например, модель Сотрудник в качестве свойства “Должность” использует модель “Должность”.
через дочернюю коллекцию. Например, модель Прайс лист имеет детализацию (табличную часть), с товарами и ценами.
Реализуем оба подхода.
Свойство - модель
В нашем примере с товаром Товар может относиться только к одной группе, то есть это характеристика товара. Добавим это свойство в Модель:
Material.model.json
| {
"dbName": "Material",
"viewName": "",
"typeName": "Material",
"primaryKeyDomain": "Material",
"storeHistory": false,
"primaryKeyProperty": "VCode",
"description": "Справочник товаров",
"properties": {
"VCode": {
"dbName": "VCode",
"viewName": "VCode",
"type": "bigint"
},
"Name": {
"dbName": "Name",
"viewName": "Name",
"type": "string",
"description": "Наименование"
},
"MaterialGroup": {
"dbName": "MaterialGroup",
"viewName": "MaterialGroup",
"type": "./MaterialGroup.model.json",
"description": "группа"
}
},
"details": {},
"rights": {
"create": ["super"],
"read": ["super"],
"update": ["super"],
"delete": ["super"]
}
}
|
Мы добавили новое свойство MaterialGroup, которое будет смотреть на модель с группами. Связь осуществляется по ключу (VCode), то есть в данной колонке будет храниться код группы из таблицы групп.
Через обновление БД добавьте колонку.

Получи новый столбец в таблице Material.

Заполним его:
| update [dbo].[Material]
set MaterialGroup = iif(VCode in (1, 2), 1, 2)
|
Результат:

Теперь добавим в таблицу с ценами небольшое условие, чтобы группа проставлялась автоматически при выборе товара.
В макете формы ModelForm.xml в Grid добавьте подписание на событие изменения значений в ячейке (cellValueChanged):
| cellValueChanged='Grid1_cellValueChanged'
|
И добавьте реализацию:
| Grid1_cellValueChanged({ args }) {
if (args.datafield == 'Material') {
this.controls.Grid1.dataSource()[args.rowindex].MaterialGroup(args.newvalue.MaterialGroup.Name)
}
}
|
Как видно по коду, в случае изменения в колонке Material, группа в текущей строке заполняется группой из нового товара (args.newvalue.MaterialGroup).
Теперь при выборе товара, группа будет проставляться автоматически из его настроек (в БД).
Дочерняя коллекция
Сделаем наш прайс лист - отдельным документом, а таблица с ценами будет его дочерней коллекцией. Схема таблиц:

Документ содержит уникальный ключ (VCode) и дату с которой прайс-лист действует (DocumentDate). Табличная часть документа - это другая таблица, которая содержит ссылку (PCode) на головную часть документа и информацию о товаре и цене.
Создадим новую модель документа PriceList.model.json
| {
"dbName": "PriceList",
"typeName": "PriceList",
"primaryKeyDomain": "PriceList",
"storeHistory": false,
"primaryKeyProperty": "VCode",
"description": "",
"properties": {
"VCode": {
"dbName": "VCode",
"type": "bigint"
},
"DocumentDate": {
"dbName": "DocumentDate",
"type": "date",
"description": "дата документа"
}
},
"details": {
"Detail": {
"foreignKeyProperty": "PCode",
"type": "./PriceListDetail.model.json"
}
},
"rights": {
"create": ["super"],
"read": ["super"],
"update": ["super"],
"delete": ["super"]
}
}
|
И модель его табличной части (по сути того, что выводит dataGrid).
Модель PriceListDetail.model.json
| {
"dbName": "PriceListDetail",
"typeName": "PriceListDetail",
"primaryKeyDomain": "PriceListDetail",
"storeHistory": true,
"primaryKeyProperty": "VCode",
"description": "",
"properties": {
"VCode": {
"dbName": "VCode",
"type": "bigint"
},
"PCode": {
"dbName": "PCode",
"type": "bigint"
},
"MaterialGroup": {
"dbName": "MaterialGroup",
"type": "string"
},
"Material": {
"dbName": "Material",
"type": "./Material.model.json"
},
"Price": {
"dbName": "Price",
"type": "money"
}
},
"details": {},
"rights": {
"create": ["super"],
"read": ["super"],
"update": ["super"],
"delete": ["super"]
}
}
|
Как видно из настроек данные в PriceListDetail связываются с PriceList через поле PCode.
Создадим эти две таблицы через «Обновление БД» и заполним данные в таблицах:
| declare @VCode int
exec @VCode = dbo.L8_sp_GenCode 'PriceList', 1
insert into [dbo].PriceList(VCode, DocumentDate)
select @VCode, getdate()
declare @VCodeDetail int
exec @VCodeDetail = dbo.L8_sp_GenCode 'PriceListDetail', 3
insert into [dbo].PriceListDetail(VCode, PCode, Material, MaterialGroup, Price)
values(@VCodeDetail, @VCode, 1, 'Фрукты', 60.88)
, (@VCodeDetail + 1, @VCode, 2, 'Фрукты', 80)
, (@VCodeDetail + 2, @VCode, 3, 'Сыры', 170.22)
|
Проверим результат:
| select * from PriceList
select * from PriceListDetail
|

Теперь остаётся лишь загрузить эту модель при открытии формы и заполнить таблицу данными из нее.
| import { Form, Colors, ModelSource } from 'ecosoft-lexema8'; // импорт компонентов из библиотеки ecosoft-lexema8
import template from './ModelForm.xml'; // импорт макета документа
import infoImg from 'current-theme/images/dark/help.png';
import PriceList_model from '../models/PriceList.model.json'
export default class ModelForm extends Form {
constructor(...args) {
super(...args);
new ModelSource(PriceList_model).load({ VCode: 1})
.done(data => {
this.controls.Grid1.dataSource = ko.mapping.fromJS(data.Detail);
this.controls.DateTimeInput1.value = data.DocumentDate;
this.controls.Grid1.addGrouping('MaterialGroup', 0);
});
}
...
|
Модель загружается с помощью класса ModelSource, но перед этим его надо импортировать из библиотеки Лексемы, а так же надо импортировать класс загружаемой модели (PriceList.model.json). После загрузки в таблицу заполнится табличная часть нашего прайс листа и настроится группировка.
Свойство dataGrid можно удалить из класса, так как данные теперь берутся из БД.
История
В Лексеме присутствует механизм отслеживания изменений данных в таблицах, на которых построены модели. Для включения этого механизма необходимо в модели указать параметр (см модель PriceListDetail.model.json):
и при обновлении БД выполнить скрипт создания триггера, который будет при изменениях данных сохранять их в “историческую” таблицу

и скрипт на вкладке История, который как раз создаёт эту самую “историческую” таблицу.

проверить ее работоспособность весьма легко, обновим какие-нибудь данные в этой таблице:
| update PriceListDetail set Price = 80 where VCode = 1
update PriceListDetail set Price = 60.88 where VCode = 1
|
В результате в исторической таблице появится запись предыдущего состояния строки.
Обратите внимание, что “историческая” таблица находится в другой БД, ее имя равно ‘имя БД данных + ‘_History’.
Наличие таких данных может существенно упростить анализ работы системы и пользователей в ней.