ConvertDataConnection

ConvertDataConnection - преобразующее загружающее соединение с данными, которое получает данные из другого загружающего соединения с данными и позволяет изменить структуру данных. Полный список селекторов для модификации структуры данных можно найти в статье справочника по синтаксису платформы WT, а здесь кратко познакомимся с часто используемыми.

Пример практического применения ConvertDataConnection рассматривается в Уроке 26. Работа с JSON на форме.

Работать будем с формой и запросами из раздела Подготовка.

Добавление новых полей

Частым случаем применения ConvertDataConnection является необходимость расширить набор полей исходного DataConnection. Например, добавить поля Added, Updated и Deleted, чтобы при редактировании записи на форме устанавливать статус, который проверять при сохранении изменений в базу данных.

Для этих целей используется селектор типа Value, который добавляет колонку с именем из атрибута Name и типом данных из атрибута DataType. Для каждой строки в ячейку новой колонки ставиться значение, указанное в качестве значения тэга. Изменить значения полей можно через set-проперти AddRow, AddRows, UpdateRow, UpdateRows, UpdateColumn и UpdateColumnCellsValues в команде типа ValueSetCommand.

<DataConnection Name="ClientConvertDataConnection" Type="ConvertDataConnection" Assembly="WorkflowServer">
  <SourceDataConnection Name="ClientPrimaryGetDataConnection" />
  <Fields>
    <Field Name="ClientId" />
    <Field Name="Title" />
    <Field Name="CityId" />
    <Field Name="Added" Type="Value" DataType="BooleanDataType">False</Field>
    <Field Name="Updated" Type="Value" DataType="BooleanDataType">False</Field>
    <Field Name="Deleted" Type="Value" DataType="BooleanDataType">False</Field>
  </Fields>
</DataConnection>

Подстановка значений

Вторым по частоте использования является селектор типа Substitution, который добавляет колонку с именем из атрибута Name, а значение для нее берет из матрицы подстановки по ключу из поля, указанному в атрибуте Field.

<DataConnection Name="ClientConvertDataConnection" Type="ConvertDataConnection" Assembly="WorkflowServer">
  <SourceDataConnection Name="ClientPrimaryGetDataConnection" />
  <Fields>
    <Field Name="ClientId" />
    <Field Name="Title" />
    <Field Name="CityId" />
    <Field Name="CityTitle" Type="Substitution" Field="CityId">
      <DataConnection SourceDataConnection="CityPrimaryGetDataConnection">
        <Fields>
          <Field Name="CityId" />
          <Field Name="Title" />
        </Fields>
      </DataConnection>
    </Field>
  </Fields>
</DataConnection>

Подстановка сработает только при обновлении ConvertDataConnection, которое будет при загрузки формы и при обновлении источника данных, если не задан элемент ManualRefresh со значением True, а так же по команде типа DataConnectionRefreshCommand.

Поэтому при добавлении записи или редактировании колонки с ключом для подстановки нужно задавать значение

Замена подстрок

Бывают ситуации, когда в SQL-запросе формируется текстовая строка, в которой необходимо заменить подстроку. Например, в строку встраивается ключ, а на форме вместо ключа должно подставиться конкретное значение.

В качестве примера в запросе будем формировать строку из фамилии клиента и в круглых скобках указывать идентификатор города. На форме в ConvertDataConnection вместо идентификатора будем подставлять название города.

Скорректируем запрос TestClientSelectSqlQuery, добавив поле TitleWithCity:

<SqlQuery Name="TestClientSelectSqlQuery">
  <Text>
    SELECT
      client_id AS "ClientId",
      title AS "Title",
      city_id AS "CityId",
      archive AS "Archive",
      title || ' (' || city_id || ')' AS "TitleWithCity"
    FROM
      template.client
    ORDER BY client_id;
  </Text>
</SqlQuery>

Добавим в ClientPrimaryGetDataConnection новое поле TitleWithCity, а затем переделаем ClientConvertDataConnection:

<DataConnection Name="ClientConvertDataConnection" Type="ConvertDataConnection" Assembly="WorkflowServer">
  <SourceDataConnection Name="ClientPrimaryGetDataConnection" />
  <Fields>
    <Field Name="ClientId" />
    <Field Name="TitleWithCity" Type="Replace">
      <DataConnection SourceDataConnection="CityPrimaryGetDataConnection">
        <Fields>
          <Field Name="CityId" />
          <Field Name="Title" />
        </Fields>
      </DataConnection>
    </Field>
  </Fields>
</DataConnection>

Для тэга <Field> в атрибуте Name укажем имя новой колонки, в которой будет происходить замена. А в качестве значения тэга <Field> передадим соединение с данными со списком городов. Это соединение будет выступать матрицей замены, где первый столбец - ключ, по которому будет идти замена.

Укажем ClientConvertDataConnection в качестве источника данных в таблице ResultDatabaseTable, и скорректируем ее колонки.

Запустим форму, чтобы проверить результат:

Форматирование строки

Бывает необходимость собрать текстовую строку, содержащую данные из других полей той же строки соединения с данными. Для этого используется селектор типа Format. В качестве значения тэга ожидается строка-шаблон, с указанием в фигурных скобках {} имен полей исходного соединения с данными, которые будут источниками значений.

Скорректируем запрос TestClientSelectSqlQuery, добавив поле CityTitle:

<SqlQuery Name="TestClientSelectSqlQuery">
  <Text>
    SELECT
      client.client_id AS "ClientId",
      client.title AS "Title",
      client.city_id AS "CityId",
      client.archive AS "Archive",
      city.title AS "CityTitle"
    FROM
      template.client
      LEFT JOIN template.city USING(city_id)
    ORDER BY client_id;
  </Text>
</SqlQuery> 

Добавим в ClientPrimaryGetDataConnection новое поле CityTitle, а затем переделаем ClientConvertDataConnection:

<DataConnection Name="ClientConvertDataConnection" Type="ConvertDataConnection" Assembly="WorkflowServer">
  <SourceDataConnection Name="ClientPrimaryGetDataConnection" />
  <Fields>
    <Field Name="ClientId" />
    <Field Name="ClientTitle" Type="Format">{Title} ({CityTitle})</Field>
  </Fields>
</DataConnection>

Укажем его в качестве источника данных в таблице ResultDatabaseTable, и скорректируем ее колонки.

Запустим форму, чтобы проверить результат:

Сложные шаблоны

Для форматирования строки по шаблону существует еще один селектор типа TemplateFormat, который позволяет использовать в шаблоне условные операторы.

В качестве шаблонизатора используется Scriban. Подробнее можно почитать по ссылке.

Давайте рассмотрим пример, добавления в имя клиента постфикса (арх.), если запись находится в архиве:

<DataConnection Name="ClientConvertDataConnection" Type="ConvertDataConnection" Assembly="WorkflowServer">
  <SourceDataConnection Name="ClientPrimaryGetDataConnection" />
  <Fields>
    <Field Name="ClientId" />
    <Field Name="Title" Type="TemplateFormat">{{Title}}{{if Archive}} (арх.){{end}}</Field>
    <Field Name="Archive" />
  </Fields>
</DataConnection>

Укажем его в качестве источника данных в таблице ResultDatabaseTable, и скорректируем ее колонки.

Запустим форму, чтобы проверить результат:

Вложенные массивы

Для обработки вложенных массивов используется селектор типа Action, который поддерживает операций по работе с массивами, перечисленные в статье Array.

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

<SqlQuery Name="TestClientSelectSqlQuery">
  <Text>
    WITH _material AS (
      SELECT
        O.client_id,
        array_agg(M.title) AS materials,
        array_agg(OP.quantity * OP.unit_price) AS total_price
      FROM
        template.order_position OP
        LEFT JOIN template.order O USING(order_id)
        LEFT JOIN template.material M USING(material_id)
        LEFT JOIN template.material_category MC USING(material_category_id)
        LEFT JOIN template.unit U USING(unit_id)
      GROUP BY O.client_id
    )
    SELECT
      C.client_id AS "ClientId",
      C.title AS "Title",
      C.city_id AS "CityId",
      C.archive AS "Archive",
      M.materials AS "Materials",
      M.total_price AS "TotalPrice"
    FROM
      template.client C
      LEFT JOIN _material M USING(client_id)
    ORDER BY client_id;
  </Text>
</SqlQuery>

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

Добавим в ClientPrimaryGetDataConnection новые поля Materials и TotalPrice, а затем переделаем ClientConvertDataConnection:

<DataConnection Name="ClientConvertDataConnection" Type="ConvertDataConnection" Assembly="WorkflowServer">
  <SourceDataConnection Name="ClientPrimaryGetDataConnection" />
  <Fields>
    <Field Name="ClientId" />
    <Field Name="Title" />
    <Field Name="MaterialsAction" Type="Action" Field="Materials">
      <StringJoin Separator=", " />
    </Field>
    <Field Name="TotalPriceAction" Type="Action" Field="TotalPrice">
      <Sum Type="DecimalDataType" />
    </Field>
  </Fields>
</DataConnection>

Укажем его в качестве источника данных в таблице ResultDatabaseTable, и скорректируем ее колонки.

Запустим форму, чтобы проверить результат:

Last updated