Перейти к содержанию

Модель. Связи#

Модель может быть связана с другими моделями:

через свойство. Например, модель Сотрудник в качестве свойства “Должность” использует модель “Должность”.

через дочернюю коллекцию. Например, модель Прайс лист имеет детализацию (табличную часть), с товарами и ценами.

Реализуем оба подхода.

Свойство - модель#

В нашем примере с товаром Товар может относиться только к одной группе, то есть это характеристика товара. Добавим это свойство в Модель:

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'

И добавьте реализацию:

1
2
3
4
5
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):

storeHistory: true

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

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

проверить ее работоспособность весьма легко, обновим какие-нибудь данные в этой таблице:

update PriceListDetail set Price = 80 where VCode = 1
update PriceListDetail set Price = 60.88 where VCode = 1

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

Обратите внимание, что “историческая” таблица находится в другой БД, ее имя равно ‘имя БД данных + ‘_History’.

Наличие таких данных может существенно упростить анализ работы системы и пользователей в ней.