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

Модель#

Для получения данных из БД в Лексеме есть два инструмента:

Модель. Даёт возможность получить одну запись из таблицы и связать ее с элементами управления на форме.

Запрос. Даёт возможность выполнять любой запрос в БД.

В этом занятии начнём изучение модели. Дополним предыдущий пример, сделав выбор товаров и групп из заранее созданного справочников, которые будут храниться в таблицах БД.

Для начала создадим новую форму. Возьмем за основу ControlsForm, скопируйте их содержимое.

ModelDemoForm.js. Заменим ссылку на макет и наименование класса.

1
2
3
4
5
6
….
import template from './ModelForm.xml'; // импорт макета документа
….
export default class ModelForm extends Form {
  constructor(...args) {
...

ModelDemoForm.xml. Заменим только наименование формы.

1
2
3
<Form writeRoles='super' title='Model Demo'>
  <ToolBar>
….

И добавим ссылку на форму в меню (units.json).

1
2
3
4
5
6
7
8
... 
     },
      {
        "caption": "Модель",
        "key": "ModelDemoForm",
        "form": "./forms/ModelDemoForm"
      }
...

Результат:

Меню.

Форма.

В каталоге проекта models создайте два файла:

Material.model.json

MaterialGroup.model.json

В Material.model.json вставим код «Шаблон Material.model.json»

{
  "dbName": "Material",
  "viewName": "",
  "typeName": "Material",
  "primaryKeyDomain": "Material",
  "storeHistory": false,
  "primaryKeyProperty": "VCode",
  "description": "Справочник товаров",
  "properties": {
    "VCode": {
      "dbName": "VCode",
      "type": "bigint"
    },
    "Name": {
      "dbName": "Name",
      "type": "string",
      "description": "Наименование"
    }
  },
  "details": {},
  "rights": {
    "create": ["super"],
    "read": ["super"],
    "update": ["super"],
    "delete": ["super"]
  }
}

В MaterialGroup.model.json вставим:

{
  "dbName": "MaterialGroup",
  "viewName": "",
  "typeName": "MaterialGroup",
  "primaryKeyDomain": "MaterialGroup",
  "storeHistory": false,
  "primaryKeyProperty": "VCode",
  "description": "Справочник групп товаров",
  "properties": {
    "VCode": {
      "dbName": "VCode",
      "viewName": "VCode",
      "type": "bigint"
    },
    "Name": {
      "dbName": "Name",
      "viewName": "Name",
      "type": "string",
      "description": "Наименование"
    }
  },
  "details": {},
  "rights": {
    "create": ["super"],
    "read": ["super"],
    "update": ["super"],
    "delete": ["super"]
  }
}

Обновление БД#

Теперь надо создать соответствующие таблицы в БД. В Лексеме есть механизм «Обновление БД», позволяющий упростить эту задачу. Зайдите в новой вкладке браузера на адрес http://localhost:3337/dev#/view/migration.

Нажмите на кнопку «Загрузить». Лексема сравнит описание sql объектов в вашем проекте БД, и в случае расхождения предложит выполнить соответствующий sql-скрипт.

Выделите все строки, нажмите “Выполнить”. Если всё нормально выполнится, то во всех строках в “Статут” будет “Выполнено”.

Результат можно будет увидеть в MS SQL Management Studio (далее MSSMS).

Осталось лишь заполнить эти таблицы. Для этого в MSSMS в данной БД выполните sql скрипты:

Заполнение таблицы:

1
2
3
4
5
6
declare @VCode int
exec @VCode = dbo.L8_sp_GenCode 'Material', 3
insert into [dbo].[Material] (VCode, Name)
values (@VCode, 'Яблоки')
    , (@VCode + 1, 'Апельсины')
    , (@VCode + 2, 'Сыр Белебеевский')

Чтобы увидеть результат выполните

SELECT VCode, Name FROM [L84LexPractice].[dbo].[Material]
SELECT VCode, Name FROM [dbo].[MaterialGroup]

Аналогично заполним таблицу групп:

1
2
3
4
5
declare @VCode int
exec @VCode = dbo.L8_sp_GenCode 'MaterialGroup', 3
insert into [dbo].[MaterialGroup] (VCode, Name)
values (@VCode, 'Фрукты')
    , (@VCode + 1, 'Сыры')
SELECT VCode, Name FROM [dbo].[MaterialGroup]

Теперь осталось вывести из на форму.

Для вывода выпадающего списка в Лексеме существует элемент управления Lookup.

Заменим в модели формы ModelForm.xml тип колонки Material, прописав лукап вместо текстового поля:

1
2
3
4
5
6
<Column text='Группа' datafield='MaterialGroup' width='25%' >
            <TextBox />
          </Column>
          <Column text='Наименование' datafield='Material' width='50%' >
            <Lookup dataSource='../models/Material.model.json' showValueMember='false' />
          </Column>

MaterialGroup оставим также текстовым полем.

Взглянем на форму:

Поля со списками пустые, однако появилась возможность выбора значения из списка. Дело в том, что теперь в этих свойствах хранятся на примитивное значение (в нашем случает текст), в объект. Внесём небольшие изменения в заполняемые при загрузке формы данные:

1
2
3
4
5
6
7
get dataGrid() {
    return [
      {Price: 60.88, Material: { VCode: 1, Name: 'Яблоки' }, MaterialGroup: 'Фрукты' }, 
      {Price: 80, Material: { VCode: 2, Name: 'Апельсины' }, MaterialGroup: 'Фрукты' }, 
      {Price: 170.22, Material: { VCode: 3, Name: 'Сыр Белебеевский' }, MaterialGroup: 'Сыры' }
    ];
  }

Результат:

Лукап на форме#

Усложним вычисление на кнопке «Calс». Пусть среднее будет считаться только по какой-то конкретной группе товаров. Для этого добавим в макет лукап (“LookupMaterialGroup”), источник данных - модель групп товаров. Добавим ее в группу и немного поменяем свойства других объектов:

1
2
3
4
5
6
<Group caption='' id='gr4' editorWidth='4' showBorder='false'>
        <Button value='Calc' id='ButtonCalc' captionWidth='0' editorWidth='1' width='100%' clicked='ButtonCalc_clicked' />
        <Lookup caption='Группа' id='LookupMaterialGroup' dataSource='../models/MaterialGroup.model.json' showValueMember='false' captionWidth='1' editorWidth='2' width='100%' />
        <Break />
        <TextBox caption='Результат' id='TextBoxTabRes' captionWidth='1' editorWidth='3' width='100%' />
      </Group>

Результат:

Теперь внесем изменения в функцию вычисления среднего:

ButtonCalc_clicked() {
    let sum = 0;
    let cnt = 0;   
    this.controls.Grid1.dataSource().forEach(e => {
      if (e.MaterialGroup() == this.controls.LookupMaterialGroup.value.Name) {
        sum += e.Price();
        cnt++;
      }
    });

    this.controls.TextBoxTabRes.value = sum / cnt;
  }

Результат:

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

ButtonCalc_clicked() {
    let sum = 0;
    let cnt = 0;
    const mg = (this.controls.LookupMaterialGroup.value || {}).Name || '';
    this.controls.Grid1.dataSource().forEach(e => {
      if (mg == '' || e.MaterialGroup() == mg) {
        sum += e.Price();
        cnt++;
      }
    });

    this.controls.TextBoxTabRes.value = sum / cnt;
  }

Результат: