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

Запрос#

Помимо модели еще одним источником информации от БД может быть sql-запрос. Его результат можно вывести как в грид (grid.dataSource = массив данных от запроса), так и в лукапе (источником данных для списка указывается не модель, а запрос).

Создадим новую форму, в ней выведем в информацию по всем товарам из всех прайсов, собранную с помощью sql-запроса. Так же добавим условие в виде лукапа с товарами, но он будет построен не на модели, а на запросе.

Создайте в каталоге forms файлы PriceListAnalytForm.xml

<Form writeRoles='super' title='Прайс листы - Аналитическая форма'>
  <ToolBar>
    <Tool id="toolBarItemExit" caption="Закрыть" image="current-theme/images/leftNavBar/close.png" clicked='toolBarItemExit_clicked'/>
  </ToolBar>
  <Layout type='bootstrap' >
    <Group id='gr1' editorWidth='12' showBorder='true' >
    </Group>
    <Group caption='Результат' id='gr2' editorWidth='12' >
      <Grid caption='Товары' id='Grid1' bind='Detail' editorWidth='12' selectionMode='multiplecellsadvanced' height='400px' toolbarVisible='false' >
        <Column text='Дата документа' datafield='DocumentDate' cellsformat='dd.MM.yyyy' width='10%' >
          <DateTimeInput />
        </Column>
        <ColumnGroup name="group1" text='Товар'> 
          <Column text='Группа' datafield='MaterialGroup' width='15%' >
            <TextBox />
          </Column>
          <Column text='Наименование' datafield='Material' width='50%' >
            <TextBox />
          </Column>
        </ColumnGroup>
        <Column text='Цена' datafield='Price' width='15%' cellsformat='D2' >
          <NumberInput />
        </Column>
      </Grid>
    </Group>
  </Layout>
</Form>

и файл PriceListAnalytForm.js

import { Form } from 'ecosoft-lexema8'; // импорт компонентов из библиотеки ecosoft-lexema8
import template from './PriceListAnalytForm.xml'; // импорт макета документа
export default class PriceListAnalytForm extends Form {
  constructor(...args) {
    super(...args);
  }
  // макет документа
  static get template() {
    return template;
  }
  toolBarItemExit_clicked() {
    this.close();
  }
}

, и зарегистрируем ее в системе (units.json)

1
2
3
4
5
{
        "caption": "Прайс лист - Аналитическая форма",
        "key": "PriceListAnalytForm",
        "form": "./forms/PriceListAnalytForm"
      }

Результат:

Список для условия добавим позже.

Теперь создадим в Лексеме запрос. Он состоят как минимум из 2х файлов:

JSON файл, оканчивающийся на .query.json. Он нужен для регистрации в Лексеме запроса, описания входных параметров и прав доступа.

SQL файл. Он содержит сам sql-запрос.

Все запросы должны располагаться в каталоге queries. Создайте в нём два файла:

файл GetPriceLists.sql

1
2
3
4
5
6
7
8
select p.DocumentDate, p.VCode
    , Material = m.Name
    , MaterialGroup = mg.Name
    , d.Price
from dbo.PriceListDetail d
    inner join dbo.PriceList p on p.VCode = d.PCode
    inner join dbo.Material m on m.VCode = d.Material
    left join dbo.MaterialGroup mg on mg.VCode = m.MaterialGroup

и файл GetPriceLists.query.json

{
  "select": {
    "text": "./GetPriceLists.sql",
    "parameters": []
  },
  "parameters": {
  },
  "rights": {
    "create": [],
    "read": ["super"],
    "update": [],
    "delete": []
  }
}

Запрос и Grid#

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

import { Form, QuerySource } from 'ecosoft-lexema8'; // импорт компонентов из библиотеки ecosoft-lexema8
import template from './PriceListAnalytForm.xml'; // импорт макета документа
import GetPriceLists_query from '../queries/GetPriceLists.query.json';
export default class PriceListAnalytForm extends Form {
  …
  toolBarItemSearch_clicked() {
    new QuerySource(GetPriceLists_query).load()
      .done(result => {
        this.controls.Grid1.dataSource = ko.mapping.fromJS(result);
      })
  }
}

Запуск запроса выполняется с помощью объекта QuerySource, входящего в состав Лексемы. Для этого к его экземпляру (который принимает один параметр - ссылка на запрос) применить команду load. Эта команда может принимать параметры. Результатом станет объект типа Deffered, который вернёт результат запроса.

Далее этот результат вставляется в грид.

Результат:

Чтобы лучше увидеть результат запроса создайте несколько прайс листов на разную дату. В моем случае запрос вернул следующий результат:

Запрос и Lookup#

Добавим на форму фильтр - товар, и сделаем так, чтобы запрос возвращал информацию только по выбранному товару.

В добавим на форму список (lookup) “Товар”, но построен он будет не на модели Товар, а на запросе. Такой подход часто применяется, так как ускорит получение списка, ведь не надо загружать множество свойств модели, которые тут по сути и не используются.

Создадим сперва запрос, он будет крайне простым:

Material.sql

select VCode, Name
from dbo.Material

Material.query.json

{
  "select": {
    "text": "./Material.sql",
    "parameters": []
  },
  "parameters": {},
  "rights": {
    "create": [],
    "read": ["super"],
    "update": [],
    "delete": []
  }
}

Добавьте в макет формы ( в группу gr1):

<Lookup caption='Товар' id='LookupMaterial' dataSource='../queries/Material.query.json' showValueMember='false' captionWidth='1' editorWidth='2' width='100%' />

Получим:

Теперь его надо передать параметром в запрос GetPriceLists:

1
2
3
4
5
6
7
8
9
toolBarItemSearch_clicked() {
    const qParam = {
      Material: (this.controls.LookupMaterial.value || {}).VCode || 0
    }
    new QuerySource(GetPriceLists_query).load(qParam)
      .done(result => {
        this.controls.Grid1.dataSource = ko.mapping.fromJS(result);
      })
  }

Добавим объявление этого параметра в самом запросе:

GetPriceLists.query.json

{
  "select": {
    "text": "./GetPriceLists.sql",
    "parameters": ["Material"]
  },
  "parameters": {
    "Material": "bigint"
  },
  "rights": {
    "create": [],
    "read": ["super"],
    "update": [],
    "delete": []
  }
}

Запрос:

GetPriceLists.sql

1
2
3
4
5
6
7
8
9
select p.DocumentDate, p.VCode
  , Material = m.Name
  , MaterialGroup = mg.Name
  , d.Price
from dbo.PriceListDetail d
  inner join dbo.PriceList p on p.VCode = d.PCode
  inner join dbo.Material m on m.VCode = d.Material
  left join dbo.MaterialGroup mg on mg.VCode = m.MaterialGroup
where d.Material = @Material

Результат:

Немного усложним условие в sql-запросе, чтобы в случае, если товар не выбран, выводились все товары.

1
2
3
….
where (@Material > 0 and d.Material = @Material)
  or (@Material = 0)

Синхронизация#

В проекте Лексемы можно хранить необходимые для проекта sql объекты (функции, процедуры, представления) и через Обновление БД обновлять их в БД. Все они хранятся в каталоге проекта sqlObjects.

Для того, чтобы это сделать, сперва создадим такой sql объект. Перенесём содержимое запроса GetPriceLists.sql в функцию, а в теле запроса будем только её вызыввать.

Создание sql функции:

SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE FUNCTION dbo.GetPriceLists
(    
    @Material bigint
)
RETURNS TABLE
AS
RETURN
(
    select p.DocumentDate, p.VCode
    , Material = m.Name
    , MaterialGroup = mg.Name
    , d.Price
    from dbo.PriceListDetail d
    inner join dbo.PriceList p on p.VCode = d.PCode
    inner join dbo.Material m on m.VCode = d.Material
    left join dbo.MaterialGroup mg on mg.VCode = m.MaterialGroup
    where (@Material > 0 and d.Material = @Material)
    or (@Material = 0)
)

Теперь ее можно увидеть в дереве sql объектов MSSMS:

В запросе GetPriceLists.sql заменим выборку на вызов этой функции:

select * from dbo.GetPriceLists(@Material)

Теперь с помощью еще одного инструмента разработчика (помимо Обновления БД) - Синхронизации перенесем эту функцию в наш проект.

Перейдите по адресу http://localhost:3337/dev#/view/synchronize

На открывшейся форме нажмите “Загрузить”.

В списке должна появиться наша функция. Выберите строку с ней (галочка слева) и нажмите “Выполнить”. В результате код создания функции должен появиться в вашем проекте в каталоге sqlQbjects.

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