# Урок 1. Форма списка и добавление записей

В разделе [Платформа Workflow Technology](https://wfsys.gitbook.io/workflow-technology) мы познакомились с [архитектурой платформы](https://wfsys.gitbook.io/workflow-technology/platform-description/platform-architecture), [составом проекта](https://wfsys.gitbook.io/workflow-technology/setting-up-dev-environment/educational-project#project-structure) и настройкой взаимосвязи его компонент. [Развернули серверную и клиентскую части](https://wfsys.gitbook.io/workflow-technology/setting-up-dev-environment/manual-deployment-project) учебного проекта. И [добавили исходники учебного проекта](https://wfsys.gitbook.io/workflow-technology/setting-up-dev-environment/create_project#adding-project-to-editor) в редактор Workflow XML Editor.

Пришло время развивать наш проект и знакомиться с возможностями редактора и платформы.&#x20;

Начнем мы с того, что на стартовой форме создадим таблицу для списка городов с кнопкой добавления записи в таблицу и кнопкой сохранения изменений в базу данных. Так же создадим форму для карточки сущности с текстовым полем "Наименование".

В этом уроке мы научимся:

* получать данные из таблицы в базе данных;
* добавлять записи в таблицу в базе данных;
* создавать и открывать новые формы;
* передавать данные с дочерней формы на родительскую;
* редактировать таблицу на форме.

## Форма списка

Список будет на стартовой форме в виде таблицы с колонками: "№" (Порядковый номер записи) и "Наименование". Справа от таблицы будет размещена кнопка добавления записи в таблицу. По этой кнопке будет открываться форма карточки сущности. Под таблицей будет располагаться кнопка для сохранения изменений в базе данных.

По завершению этого этапа мы с вами получим форму вида:

<figure><img src="https://3019442075-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-M_eBlWEU4C3o2GVEAAr%2Fuploads%2FqedQrqmBM5EAgbj9Bnol%2Fimage.png?alt=media&#x26;token=a48a86f8-641d-49d3-91c9-bba30c15f331" alt=""><figcaption></figcaption></figure>

Перейдем в Eclipse и откроем файл стартовой формы (TemplateStart.xml). Первым делом давайте изменим заголовок и размер формы.

Параметру формы **Title** зададим новое значение "Города".

{% code title="TemplateStart.xml" %}

```markup
<Parameters>
  <Parameter Name="Title">Города</Parameter>
</Parameters>
```

{% endcode %}

В тэге `<Form>` для атрибутов `Width` и `Height` зададим значение **500** и **300** соответственно. И добавим атрибут `FormBorderStyle` со значением **Sizable**. Это позволит изменять размер окна.

{% code title="TemplateStart.xml" %}

```markup
<Form Name="TemplateStartForm" Width="500" Height="300" FormBorderStyle="Sizable" StartPosition="CenterScreen" FontStyle="ThemeFontStyle" ForeColor="ThemeForeColor" BackColor="ThemeBackgroundColor" ValidationType="Flat" FlatColor="ThemeFlatColor" FlatWidth="2" StatusBar="True" MaximizeBox="True">
```

{% endcode %}

### Создание таблицы

Давайте добавим таблицу (объект типа [DatabaseTable](https://wfsys.gitbook.io/workflow-forms-syntax/workflow_forms/objects/databasetable)) на форму. Для этого поместите курсор внутри объекта **ContentPanel**, после тэга `<BackColor>`. Начните писать, затем нажмите на сочетание клавиш Ctrl+Space. Откроется окно автозаполнения.

![](https://3019442075-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-M_eBlWEU4C3o2GVEAAr%2F-M_ttWOdIUStDcspADDu%2F-M_tt__QuqtK9jPBtQp4%2F1.1.%20%D0%98%D1%81%D0%BF%D0%BE%D0%BB%D1%8C%D0%B7%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5%20%D0%BF%D0%BE%D0%B4%D1%81%D0%BA%D0%B0%D0%B7%D0%BA%D0%B8%20%D0%B4%D0%BB%D1%8F%20%D1%8D%D0%BB%D0%B5%D0%BC%D0%B5%D0%BD%D1%82%D0%BE%D0%B2%20%D0%BA%D0%BE%D0%B4%D0%B0.png?alt=media\&token=a157182c-8bde-4ec6-9818-74d8d9002d70)

Выберете в списке автозаполнения нужный элемент. Редактор подставит весь обязательный и необходимый код. Останется только задать нужные значения.

{% code title="TemplateStart.xml" %}

```markup
<MyObject Name="DatabaseTable" Type="DatabaseTable" Assembly="ComplexControls">
  <Top></Top>
  <Left></Left>
  <Height></Height>
  <Width></Width>
  <AllowResizeColumns Value="False" />
  <AllowResizeRows Value="False" />
  <AllowInsert></AllowInsert>
  <AllowUpdate></AllowUpdate>
  <AllowDelete></AllowDelete>
  <AutoSizeColumnsMode Value="Fill" />
  <SourceDataConnection Name="" />
  <Columns></Columns>
</MyObject>
```

{% endcode %}

Первым делом зададим нашему объекту имя. Например, **CityDatabaseTable**. Подробно про тип DatabaseTable можете прочитать по [ссылке](https://wfsys.gitbook.io/workflow-forms-syntax/workflow_forms/objects/databasetable). А сейчас рассмотрим предложенные редактором элементы.

#### Элементы, общие для всех графических объектов

Тэги [`<Top>`](https://wfsys.gitbook.io/workflow-forms-syntax/workflow_forms/objects#top) и [`<Left>`](https://wfsys.gitbook.io/workflow-forms-syntax/workflow_forms/objects#left) задают координаты верхней левой точки объекта в пределах контейнера, в котором расположен объект. Ожидаются положительные целочисленные значения. Для таблицы CityDatabaseTable контейнером является панель **ContentPanel**, для которой контейнером является сама форма.

Тэги [`<Height>`](https://wfsys.gitbook.io/workflow-forms-syntax/workflow_forms/objects#height)и [`<Width>`](https://wfsys.gitbook.io/workflow-forms-syntax/workflow_forms/objects#width) задают высоту и ширину объекта. Ожидаются положительные целочисленные значения.

Значения этих элементов можно задать постоянными. Для `<Top>` и `<Left>` укажем значения **5** и **10** соответственно.

А можно задать гибкие значения, привязав к свойствам других объектов. Для этого можно использовать универсальные значения [Calculate](https://wfsys.gitbook.io/workflow-forms-syntax/workflow_forms/values/calculate) или [Formula](https://wfsys.gitbook.io/workflow-forms-syntax/workflow_forms/values/formula) для вычисления числового выражения. Или напрямую привязать к свойству другого объекта. Это позволит динамически изменять размер и положение объектов на форме при изменении размеров самого окна.

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

```markup
<Height>
  <Calculate>
    <Expression>{0} - {1}*2</Expression>
    <Items>
      <Item>
        <Object Name="ContentPanel">
          <Property Name="Height" />
        </Object>
      </Item>
      <Item>
        <Object Name="CityDatabaseTable">
          <Property Name="Top" />
        </Object>
      </Item>
    </Items>
  </Calculate>
</Height>
```

Для вычисления ширины таблицы самостоятельно переделайте код, используя ширину контейнера и свойство **Left** самой таблицы.

#### Элементы, характерные только для таблицы DatabaseTable

* `<AllowResizeColumns>` - признак, определяющий, может ли пользователь изменять ширину столбцов посредством графического интерфейса таблицы. Значение атрибута `Value` оставим по умолчанию;
* `<AllowResizeRows>` - признак, определяющий, может ли пользователь изменять высоту строк посредством графического интерфейса таблицы. Оставим значение атрибута `Value` по умолчанию;
* `<AllowInsert>`, `<AllowUpdate>` и `<AllowDelete>` - признаки, определяющие, может ли пользователь редактировать строки в таблице посредством графического интерфейса таблицы. Всем признакам укажем значение **False**, т.к. для редактирования таблицы будем использовать отдельную форму и набор set-проперти таблицы;
* `<AutoSizeColumnsMode>` - название типа автоматического изменения ширины столбцов таблицы. Оставим значение атрибута `Value` по умолчанию;
* `<SourceDataConnection>` - загружающее соединение с данными, данные которого будут использоваться в таблице;
* `<Columns>` - содержит список столбцов таблицы.

У нас пока что нет источника данных для таблицы поэтому можем удалить или закомментировать тэг `<SourceDataConnection>`, чтобы редактор не выкидывал ошибку, и форма корректно открывалась.

{% hint style="info" %}
Для того чтобы закомментировать часть кода, нужно выделить код и нажать сочетание клавиш **Ctrl+<**. Для снятия комментария с кода достаточно поставить курсор в любое место комментария и нажать эту же комбинацию клавиш.
{% endhint %}

Добавим колонки в таблицу. Нам нужно создать три колонки:

* **CityId** - скрытая служебная колонка с идентификатором записи в базе;
* **RowNumber** - порядковый номер отображаемой записи;
* **Title** - наименование города, которое введет пользователь.

```markup
<Columns>
  <Column Name="CityId" Type="DatabaseTableColumnTextBox" Assembly="DatabaseTableColumnControls">
    <Visible>False</Visible>
  </Column>
  <Column Name="RowNumber" Type="DatabaseTableColumnTextBox" Assembly="DatabaseTableColumnControls">
    <Title>№</Title>
    <Width>30</Width>
    <AutoFill Type="RowNumber" />
    <Alignment Value="MiddleCenter" />
    <AutoSizeMode Value="None" />
  </Column>
  <Column Name="Title" Type="DatabaseTableColumnTextBox" Assembly="DatabaseTableColumnControls">
    <Title>Наименование</Title>
    <Width>150</Width>
    <AutoSizeMode Value="Fill" />
  </Column>
</Columns>
```

Тэг `<AutoFill Type="RowNumber" />` отвечает за автоматическую генерацию порядкового номера строки в таблице.

{% hint style="info" %}
Для автоматического форматирования xml-кода используйте сочетание клавиш **Ctrl+Q**
{% endhint %}

В итоге синтаксис таблицы **CityDatabaseTable** будет выглядеть так:

{% code title="TemplateStart.xml" %}

```markup
<MyObject Name="CityDatabaseTable" Type="DatabaseTable" Assembly="ComplexControls">
  <Top>5</Top>
  <Left>10</Left>
  <Height>
    <Calculate>
      <Expression>{0} - {1}*2</Expression>
      <Items>
        <Item>
          <Object Name="ContentPanel">
            <Property Name="Height" />
          </Object>
        </Item>
        <Item>
          <Object Name="CityDatabaseTable">
            <Property Name="Top" />
          </Object>
        </Item>
      </Items>
    </Calculate>
  </Height>
  <Width>
    <Calculate>
      <Expression>{0} - {1}*2</Expression>
      <Items>
        <Item>
          <Object Name="ContentPanel">
            <Property Name="Width" />
          </Object>
        </Item>
        <Item>
          <Object Name="CityDatabaseTable">
            <Property Name="Left" />
          </Object>
        </Item>
      </Items>
    </Calculate>
  </Width>
  <AllowResizeColumns Value="False" />
  <AllowResizeRows Value="False" />
  <AllowInsert>False</AllowInsert>
  <AllowUpdate>False</AllowUpdate>
  <AllowDelete>False</AllowDelete>
  <AutoSizeColumnsMode Value="Fill" />
  <!--<SourceDataConnection Name="" />-->
  <Columns>
    <Column Name="CityId" Type="DatabaseTableColumnTextBox" Assembly="DatabaseTableColumnControls">
      <Visible>False</Visible>
    </Column>
    <Column Name="RowNumber" Type="DatabaseTableColumnTextBox" Assembly="DatabaseTableColumnControls">
      <Title>№</Title>
      <Width>30</Width>
      <AutoFill Type="RowNumber" />
      <Alignment Value="MiddleCenter" />
      <AutoSizeMode Value="None" />
    </Column>
    <Column Name="Title" Type="DatabaseTableColumnTextBox" Assembly="DatabaseTableColumnControls">
      <Title>Наименование</Title>
      <Width>150</Width>
      <AutoSizeMode Value="Fill" />
    </Column>
  </Columns>
</MyObject>
```

{% endcode %}

Давайте посмотрим, что у нас получилось. Убедитесь, что запущен сервер. Если нет, то запустите файл *\_start.bat* из папки, в которую [разворачивали серверную часть](https://wfsys.gitbook.io/workflow-technology/setting-up-dev-environment/manual-deployment-project#server) приложения, например, *D:\WorkflowEngine\Template*. Запустите приложение *WorkflowForms.exe* из папки, в которую [разворачивали клиентскую часть](https://wfsys.gitbook.io/workflow-technology/setting-up-dev-environment/manual-deployment-project#client), например, *D:\WorkflowForms\Template*. Если клиентская часть уже была запущена, то лучше закрыть и запустить заново.

{% hint style="warning" %}
К сожалению, запуск WT-приложения из Eclipse не доступен.
{% endhint %}

<figure><img src="https://3019442075-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-M_eBlWEU4C3o2GVEAAr%2Fuploads%2FPWt34aZonPtoxwQV9ytL%2Fimage.png?alt=media&#x26;token=ab0c629b-0350-41b8-ba66-deaaa506ff9c" alt=""><figcaption></figcaption></figure>

### Создание кнопок

Для кнопок нам понадобятся иконки. Скачайте архив с изображениями и разархивируйте его в папку проекта **\Template\Projects\1. Template\Forms\Images\24x24**.

{% file src="<https://3019442075-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-M_eBlWEU4C3o2GVEAAr%2F-Malff_dcwXsdfvrSfKh%2F-MalfrZsUSRmsbNy_bCg%2Flesson1-Images.zip?alt=media&token=c8e5b7a0-c54c-40ef-8a25-b241695fbfa7>" %}
Иконки для кнопок
{% endfile %}

#### Кнопка добавления записей

Добавим кнопку (объект типа [Button](https://wfsys.gitbook.io/workflow-forms-syntax/workflow_forms/objects/button)), по которой будет открываться форма с карточкой города. Добавьте в **ContentPanel** вслед за **CityDatabaseTable** следующий код:

{% code title="TemplateStart.xml" %}

```markup
<MyObject Name="CityAddButton" Type="Button" Assembly="BaseControls">
  <Top>
    <Object Name="CityDatabaseTable">
      <Property Name="Top" />
    </Object>
  </Top>
  <Left>
    <Calculate>
      <Expression>{0} + 5</Expression>
      <Items>
        <Item>
          <Object Name="CityDatabaseTable">
            <Property Name="Right" />
          </Object>
        </Item>
      </Items>
    </Calculate>
  </Left>
  <Width>40</Width>
  <Height>40</Height>
  <Hint>Добавить запись...</Hint>
  <BackgroundImage>Images\24x24\plus.png</BackgroundImage>
  <BackgroundImageLayout>Center</BackgroundImageLayout>
  <FlatStyle>Flat</FlatStyle>
  <FlatBorderSize>1</FlatBorderSize>
  <FlatBorderColor>ButtonFlatBorderColor</FlatBorderColor>
  <FlatMouseDownBackColor>ButtonFlatMouseDownBackColor</FlatMouseDownBackColor>
  <FlatMouseOverBackColor>ButtonFlatMouseOverBackColor</FlatMouseOverBackColor>
  <Commands> </Commands>
</MyObject>
```

{% endcode %}

Так как кнопка графически находится справа от таблицы, что и указано в тэге `<Left>`, то необходимо скорректировать ширину таблицы. Для этого в `<Calculate>` для тэга `<Width>` объекта **CityDatabaseTable** необходимо учесть ширину кнопки и отступ в **5** пикселей между таблицей и кнопкой. Заменим описание тэга `<Width>`объекта **CityDatabaseTable** следующим кодом:

```markup
<Width>
  <Calculate>
    <Expression>{0} - {1}*2 - {2} - 5</Expression>
    <Items>
      <Item>
        <Object Name="ContentPanel">
          <Property Name="Width" />
        </Object>
      </Item>
      <Item>
        <Object Name="CityDatabaseTable">
          <Property Name="Left" />
        </Object>
      </Item>
      <Item>
        <Object Name="CityAddButton">
          <Property Name="Width" />
        </Object>
      </Item>
    </Items>
  </Calculate>
</Width>
```

Перезапустите проект. Убедитесь, что форма успешно загружена. Проверьте расположение объектов на форме.

<figure><img src="https://3019442075-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-M_eBlWEU4C3o2GVEAAr%2Fuploads%2FzfhZ90nuw33zwyOY9SOZ%2Fimage.png?alt=media&#x26;token=8a42f90b-3deb-4e28-9a18-efad33ecbe84" alt=""><figcaption></figcaption></figure>

#### Кнопка сохранения

Кнопка "Сохранить" будет располагаться в нижней части формы (Footer). Давайте создадим новую панель, которую назовем **FootPanel**. Так же визуально отделим **FootPanel** от **ContentPanel** с помощью разделителя, в качестве которого будет выступать [Panel](https://wfsys.gitbook.io/workflow-forms-syntax/workflow_forms/objects/panel) с высотой в один пиксель. Добавьте следующий код следом за **ContentPanel**.

{% code title="TemplateStart.xml" %}

```markup
<MyObject Name="FootSeparatePanel" Type="Panel" Assembly="BaseControls">
  <Top>
    <Object Name="ContentPanel">
      <Property Name="Bottom" />
    </Object>
  </Top>
  <Left>5</Left>
  <Height>1</Height>
  <Width>
    <Calculate>
      <Expression>{0} - 10</Expression>
      <Items>
        <Item>
          <Form>
            <Property Name="Width" />
          </Form>
        </Item>
      </Items>
    </Calculate>
  </Width>
  <BackColor>ThemeSeparateBackgroundColor</BackColor>
</MyObject>

<MyObject Name="FootPanel" Type="Panel" Assembly="BaseControls">
  <Top>
    <Object Name="FootSeparatePanel">
      <Property Name="Bottom" />
    </Object>
  </Top>
  <Left>0</Left>
  <Height>40</Height>
  <Width>
    <Form>
      <Property Name="Width" />
    </Form>
  </Width>
  <TabIndex>2</TabIndex>
  <BackColor>ThemeBackgroundColor</BackColor>
  
</MyObject>
```

{% endcode %}

Теперь нам необходимо скорректировать высоту **ContentPanel**, чтобы **FootPanel** вместе с сепаратором поместились на форме. Заменим описание тэга `<Height>` объекта **ContentPanel** следующим кодом:

```markup
<Height>
  <Calculate>
    <Expression>{0} - {1} - {2} - {3}</Expression>
    <Items>
      <Item>
        <Form>
          <Property Name="Height" />
        </Form>
      </Item>
      <Item>
        <Object Name="ContentPanel">
          <Property Name="Top" />
        </Object>
      </Item>
      <Item>
        <Object Name="FootSeparatePanel">
          <Property Name="Height" />
        </Object>
      </Item>
      <Item>
        <Object Name="FootPanel">
          <Property Name="Height" />
        </Object>
      </Item>
    </Items>
  </Calculate>
</Height>
```

Добавим в **FootPanel** кнопку "Сохранить", скопировав код:

{% code title="TemplateStart.xml" %}

```markup
<MyObject Name="SaveButton" Type="Button" Assembly="BaseControls">
  <Top>5</Top>
  <Right>
    <Formula>
      <Minus DataType="IntegerDataType">
        <Item>
          <Object Name="FootPanel">
            <Property Name="Right" />
          </Object>
        </Item>
        <Item>5</Item>
      </Minus>
    </Formula>
  </Right>
  <Height>30</Height>
  <Width>200</Width>
  <TextAlign>MiddleCenter</TextAlign>
  <FontStyle>ButtonFontStyle</FontStyle>
  <ImageAlign>MiddleLeft</ImageAlign>
  <Image>Images\24x24\content-save.png</Image>
  <FlatStyle>Flat</FlatStyle>
  <FlatBorderSize>1</FlatBorderSize>
  <FlatBorderColor>ButtonFlatBorderColor</FlatBorderColor>
  <FlatMouseDownBackColor>ButtonFlatMouseDownBackColor</FlatMouseDownBackColor>
  <FlatMouseOverBackColor>ButtonFlatMouseOverBackColor</FlatMouseOverBackColor>
  <Text>Сохранить</Text>
  <Commands> </Commands>
</MyObject>
```

{% endcode %}

Перезапустите проект. Убедитесь, что форма успешно загружена. Проверьте расположение объектов на форме.

<figure><img src="https://3019442075-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-M_eBlWEU4C3o2GVEAAr%2Fuploads%2FyHAOnwv4yJ437S3MrP8q%2Fimage.png?alt=media&#x26;token=caf7b5cc-b005-4e36-8135-9fecc23267d6" alt=""><figcaption></figcaption></figure>

### Загрузка данных из базы данных на форму

#### Создание таблицы city в базе данных

Перейдем в программу для управления СУБД PostgreSQL (например, pgAdmin III). И для нашей базы данных **template\_project** откроем окно выполнения пользовательских SQL-скриптов и выполним следующий скрипт:

```sql
CREATE SEQUENCE template.city_id_seq;

CREATE TABLE template.city
(
  city_id smallint NOT NULL DEFAULT nextval('template.city_id_seq'::regclass),
  title character varying,
  CONSTRAINT pk_city_id PRIMARY KEY (city_id)
);
```

{% hint style="info" %}
Последовательность в PostgreSQL обычно используется для автоинкремента первичных ключей в таблицах.
{% endhint %}

{% hint style="warning" %}
Все имена в базе данных должны задаваться строчными буквами.
{% endhint %}

#### Описание запроса для чтения таблицы city базы данных

Вернемся в Eclipse и перейдем в файл описания работы серверной части приложения (Template.xml).

Добавим запрос для чтения данных из таблицы **template.city** в процесс. Для этого расположим в тэге `<SqlQueries>` вложенный тэг `<SqlQuery>` со следующими параметрами:

{% code title="Template.xml" %}

```markup
<SqlQuery Name="CitySelectSqlQuery">
  <Text>
    SELECT
      city_id AS "CityId",
      title AS "Title"
    FROM
      template.city
    ORDER BY title;
  </Text>
</SqlQuery>
```

{% endcode %}

Далее этот запрос следует добавить в разрешение. Для этого расположим в тэге `<Permissions>` вложенный тэг `<Permission>` со следующими параметрами:

{% code title="Template.xml" %}

```markup
<Permission Name="CityViewSqlQueryPermission" Type="SqlQueryPermission">
  <SqlQueries>
    <SqlQuery Name="CitySelectSqlQuery" />
  </SqlQueries>
</Permission>
```

{% endcode %}

После чего данное разрешение следует добавить в роль для просмотра списка. Для этого расположим в тэге `<Roles>` вложенный тэг `<Role>` со следующими параметрами:

{% code title="Template.xml" %}

```markup
<Role Name="CityViewRole">
  <Permissions>
    <Permission Name="CityViewSqlQueryPermission" />
  </Permissions>
</Role>
```

{% endcode %}

Затем роли необходимо распределить по группам. В тэге `<Groups>` вложенные тэги `<Group>` должны иметь названия, которые совпадают с названиями групп в таблице group. Т.к. в проекте пока не реализована авторизация, то в программе мы будем работать под анонимным пользователем (WS. Гость). Этот пользователь состоит в группе **GuestGroup**. Добавим в тэг `<Groups>`вложенный тэг `<Group>`для этой группы. И назначим группе роль для просмотра списка городов.

{% code title="Template.xml" %}

```markup
<Group Name="GuestGroup">
  <Roles>
    <Role Name="CityViewRole" />
  </Roles>
</Group>
```

{% endcode %}

#### Получение данных с сервера на форме

Перейдем в файл описания стартовой формы (TemplateStart.xml).

Добавим загружающее соединение с данными (объект типа [PrimaryGetDataConnection](https://wfsys.gitbook.io/workflow-forms-syntax/workflow_forms/dataconnections/primary_dc)). Для этого расположим в тэге `<DataConnections>` вложенный тэг `<DataConnection>` со следующими параметрами:

{% code title="TemplateStart.xml" %}

```markup
<DataConnection Name="CityPrimaryGetDataConnection" Type="PrimaryGetDataConnection" Assembly="DataConnections">
  <SqlQuery Name="CitySelectSqlQuery" Type="Select">
    <Workflow Name="Template" />
    <Fields>
      <Field Name="CityId" />
      <Field Name="Title" />
    </Fields>
  </SqlQuery>
</DataConnection>
```

{% endcode %}

* `<SqlQuery>` - имя запроса для получения данных. Ожидается название одного из запросов, описанных в серверном XML-файле;
* `<Workflow>` - имя процесса, в рамках которого происходит запрос;
* `<Field>` - название поля запроса, которое будет использоваться на форме. Ожидается название одного из полей, возвращаемых запросом.

С помощью **CityPrimaryGetDataConnection** мы получим на форме виртуальную таблицу (двумерный массив данных с именованными столбцами) с определенными полями, которая будет соответствовать результатам запроса **CitySelectSqlQuery**, описанного в серверном XML-файле.

{% hint style="warning" %}
Названия полей в DataConnection должны полностью (вплоть до регистра!) совпадать с полями или их алиасами в запросе.
{% endhint %}

Теперь необходимо таблице **CityDatabaseTable** в качестве источника данных указать только что созданный **CityPrimaryGetDataConnection**. Для этого раскомментируем тэг `<SourceDataConnection>`, и в качестве значения аргумента Name укажем имя DataConnection'а.

В итоге синтаксис таблицы **CityDatabaseTable** будет выглядеть так:

{% code title="TemplateStart.xml" %}

```markup
<MyObject Name="CityDatabaseTable" Type="DatabaseTable" Assembly="ComplexControls">
  <Top>5</Top>
  <Left>10</Left>
  <Height>
    <Calculate>
      <Expression>{0} - {1}*2</Expression>
      <Items>
        <Item>
          <Object Name="ContentPanel">
            <Property Name="Height" />
          </Object>
        </Item>
        <Item>
          <Object Name="CityDatabaseTable">
            <Property Name="Top" />
          </Object>
        </Item>
      </Items>
    </Calculate>
  </Height>
  <Width>
    <Calculate>
      <Expression>{0} - {1}*2 - {2} - 5</Expression>
      <Items>
        <Item>
          <Object Name="ContentPanel">
            <Property Name="Width" />
          </Object>
        </Item>
        <Item>
          <Object Name="CityDatabaseTable">
            <Property Name="Left" />
          </Object>
        </Item>
        <Item>
          <Object Name="CityAddButton">
            <Property Name="Width" />
          </Object>
        </Item>
      </Items>
    </Calculate>
  </Width>
  <AllowResizeColumns Value="False" />
  <AllowResizeRows Value="False" />
  <AllowInsert>False</AllowInsert>
  <AllowUpdate>False</AllowUpdate>
  <AllowDelete>False</AllowDelete>
  <AutoSizeColumnsMode Value="Fill" />
  <SourceDataConnection Name="CityPrimaryGetDataConnection" />
  <Columns>
    <Column Name="CityId" Type="DatabaseTableColumnTextBox" Assembly="DatabaseTableColumnControls">
      <Visible>False</Visible>
    </Column>
    <Column Name="RowNumber" Type="DatabaseTableColumnTextBox" Assembly="DatabaseTableColumnControls">
      <Title>№</Title>
      <Width>30</Width>
      <AutoFill Type="RowNumber" />
      <Alignment Value="MiddleCenter" />
      <AutoSizeMode Value="None" />
    </Column>
    <Column Name="Title" Type="DatabaseTableColumnTextBox" Assembly="DatabaseTableColumnControls">
      <Title>Наименование</Title>
      <Width>150</Width>
      <AutoSizeMode Value="Fill" />
    </Column>
  </Columns>
</MyObject>
```

{% endcode %}

Перезапустите проект. Убедитесь, что форма успешно загружена, и в журнале нет никаких сообщений об ошибках.

## Карточка города

Пришло время создать форму, на которой мы сможем редактировать информацию по городу.

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

Но для начала подключим к проекту готовые шаблоны форм. Они ускорят процесс создания новых форм.

### Подключение шаблонов к проекту

Скачаем архив с шаблонами и распакуем его в удобное место. Например, в папку проекта **\Template\Projects\1. Template\Patterns**.

{% file src="<https://3019442075-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-M_eBlWEU4C3o2GVEAAr%2Fuploads%2FMmmhuvAhbWiO6EB2F242%2Flesson1-Patterns.zip?alt=media&token=f80bb6a9-4b63-486d-8379-ee94871f4721>" %}
Шаблоны форм
{% endfile %}

Вернемся в Eclipse и перейдем в свойства проекта, используя контекстное меню. Кликнем правой кнопкой мыши по имени проекта в окне Project Explorer и в появившемся меню выберем пункт **Properties**. И в открывшемся окне свойств проекта в левой части перейдем к секции **Patterns**.

<figure><img src="https://3019442075-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-M_eBlWEU4C3o2GVEAAr%2Fuploads%2FnOSNwn9CJIvWTfwdiLdV%2Fimage.png?alt=media&#x26;token=dfbd58a1-4bf5-44f4-8456-fae04de297eb" alt=""><figcaption></figcaption></figure>

В правой части окна в поле **Project patterns path** укажем путь до папки с паттернами. Жмем OK.

Чтобы Eclipse корректно подтянул изменения паттернов, воспользуемся кнопкой **Reload patterns**, расположенной на панели инструментов.

<figure><img src="https://3019442075-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-M_eBlWEU4C3o2GVEAAr%2Fuploads%2FSkxbgkBDAHFGDLPVFzXV%2Fimage.png?alt=media&#x26;token=4007ba25-c1f6-4f3b-a5be-58e62604b0a9" alt=""><figcaption></figcaption></figure>

### Создание формы с помощью шаблона

Для создания формы с помощью шаблона используем пункт меню **File** -> **New** -> **Apply Workflow Pattern**.

<figure><img src="https://3019442075-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-M_eBlWEU4C3o2GVEAAr%2Fuploads%2FQZwi8pN76rftw40j0G7k%2Fimage.png?alt=media&#x26;token=6e9bdf20-9cbe-432e-ae07-9bf09b82279e" alt=""><figcaption></figcaption></figure>

В открывшемся диалоговом окне Workflow Editor отображается список шаблонов форм, в котором есть два шаблона: Empty Form (пустая форма с хэдером) и Empty Form With Footer (пустая форма с хэдером и футером).

<figure><img src="https://3019442075-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-M_eBlWEU4C3o2GVEAAr%2Fuploads%2Ft569YTmoIZaIHgD6sd9t%2Fimage.png?alt=media&#x26;token=ee17005c-44f7-4ed1-882b-c6fc236ecf55" alt=""><figcaption></figcaption></figure>

Для задачи создания формы карточки города выберем шаблон **Empty Form with Footer**. Этот шаблон уже содержит код формы с основными элементами. И нам останется только добавить нужное поле и реализовать логику передачи данных на родительскую форму. Жмем Finish.

Появилось окно настроек паттерна:

<figure><img src="https://3019442075-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-M_eBlWEU4C3o2GVEAAr%2Fuploads%2F7SlC0IfBYn0ukzGcU5iB%2Fimage.png?alt=media&#x26;token=7729f6f5-3b46-4ffd-b2a8-76a2c8f17cb2" alt=""><figcaption></figcaption></figure>

* **Имя формы**: это постфикс для имени файла, пишем "CityEdit". И т.к. процесс имеет название Template, то имя файла созданной формы будет TemplateCityEdit.xml;
* **Заголовок формы**: текст, который будет отображаться в хэдере формы, пишем "Добавление города";
* **Имя кнопки в футере**: имя объекта, которое будет использоваться на форме. Пишем SaveButton;
* **Текст кнопки в футере**: видимый текст на кнопке. Оставим без изменения;
* **Иконка на кнопке в футере**: путь до файла с графическим содержанием относительно папки \Forms\Images\24x24, которое будет отображаться на кнопке. Оставим без изменения. Значение по умолчанию соответствует ранее скачанному и размещенному в проекте файлу.

Жмем Finish.

Редактор создаст форму и сразу же ее откроет. В окне Project Explorer в ветке проекта увидим только что созданную форму TemplateCityEdit.xml:

<figure><img src="https://3019442075-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-M_eBlWEU4C3o2GVEAAr%2Fuploads%2Fmq2poul5Bzc3zpI56Qkg%2Fimage.png?alt=media&#x26;token=cdbc65b0-8e72-4a0b-ad6b-59ef34a043fd" alt=""><figcaption></figcaption></figure>

### Открытие формы по кнопке

Перейдем в файл стартовой формы (TemplateStart.xml) и реализуем команду открытия формы будущей карточки города. Для этого в тэг `<Commands>` самой формы добавим команду [FormShowCommand](https://wfsys.gitbook.io/workflow-forms-syntax/workflow_forms/commands/form_show_command) вида:

{% code title="TemplateStart.xml" %}

```markup
<Command Name="CityAddFormShowCommand" Type="FormShowCommand" Assembly="Commands">
  <Xml Type="Path">TemplateCityEdit.xml</Xml>
  <Show Type="Modal" />
</Command>
```

{% endcode %}

В качестве значения тэга `<Xml>` укажем имя файла карточки редактирования города. В атрибуте `Type` тэга `<Show>` стоит значение **Modal**, это означает, что форма будет открываться в модальном режиме. Особенности работы с модальными формами рассмотрим на следующем уроке.

Теперь нужно на кнопке **CityAddButton** в тэге `<Commands>` прописать вызов этой команды. Таким образом, синтаксис кнопки добавления города будет иметь вид:

{% code title="TemplateStart.xml" %}

```markup
<MyObject Name="CityAddButton" Type="Button" Assembly="BaseControls">
  <Top>
    <Object Name="CityDatabaseTable">
      <Property Name="Top" />
    </Object>
  </Top>
  <Left>
    <Calculate>
      <Expression>{0} + 5</Expression>
      <Items>
        <Item>
          <Object Name="CityDatabaseTable">
            <Property Name="Right" />
          </Object>
        </Item>
      </Items>
    </Calculate>
  </Left>
  <Width>40</Width>
  <Height>40</Height>
  <Hint>Добавить запись...</Hint>
  <BackgroundImage>Images\24x24\plus.png</BackgroundImage>
  <BackgroundImageLayout>Center</BackgroundImageLayout>
  <FlatStyle>Flat</FlatStyle>
  <FlatBorderSize>1</FlatBorderSize>
  <FlatBorderColor>ButtonFlatBorderColor</FlatBorderColor>
  <FlatMouseDownBackColor>ButtonFlatMouseDownBackColor</FlatMouseDownBackColor>
  <FlatMouseOverBackColor>ButtonFlatMouseOverBackColor</FlatMouseOverBackColor>
  <Commands>
    <Command Name="CityAddFormShowCommand" />
  </Commands>
</MyObject>
```

{% endcode %}

Перезапустите проект. Убедитесь, что форма успешно загружена, и по кнопке "Добавить запись..." открывается форма будущей карточки города.

### Заполнение формы объектами

Вернемся в файл новой формы (**TemplateCityEdit.xml**).

{% hint style="info" %}
Для быстрого перемещения к описанию объекта зажмите клавишу Ctrl и кликните левой кнопкой мыши по имени объекта, в месте его использования. Этот трюк работает с объектами MyObject, командами, файлами форм и именами SQL-запросов.
{% endhint %}

Добавим на форму в панель **ContentPanel** текстовое поле [TextBox](https://wfsys.gitbook.io/workflow-forms-syntax/workflow_forms/objects/textbox) для ввода значения и [Label](https://wfsys.gitbook.io/workflow-forms-syntax/workflow_forms/objects/label) с текстом "Наименование" для описания текстового поля.

{% code title="TemplateCityEdit.xml" %}

```markup
<MyObject Name="TitleLabel" Type="Label" Assembly="BaseControls">
  <Top>5</Top>
  <Left>10</Left>
  <Width>
    <Calculate>
      <Expression>{0} - {1} - 10</Expression>
      <Items>
        <Item>
          <Object Name="ContentPanel">
            <Property Name="Width" />
          </Object>
        </Item>
        <Item>
          <Object Name="TitleLabel">
            <Property Name="Left" />
          </Object>
        </Item>
      </Items>
    </Calculate>
  </Width>
  <Height>20</Height>
  <TextAlign>MiddleLeft</TextAlign>
  <FontStyle>LabelFontStyle</FontStyle>
  <ForeColor>LabelForeColor</ForeColor>
  <Text>Наименование</Text>
</MyObject>

<MyObject Name="TitleTextBox" Type="TextBox" Assembly="BaseControls">
  <Top>
    <Object Name="TitleLabel">
      <Property Name="Bottom" />
    </Object>
  </Top>
  <Left>
    <Object Name="TitleLabel">
      <Property Name="Left" />
    </Object>
  </Left>
  <Width>
    <Calculate>
      <Expression>{0} - {1} - 10</Expression>
      <Items>
        <Item>
          <Object Name="ContentPanel">
            <Property Name="Width" />
          </Object>
        </Item>
        <Item>
          <Object Name="TitleTextBox">
            <Property Name="Left" />
          </Object>
        </Item>
      </Items>
    </Calculate>
  </Width>
  <Text> </Text>
</MyObject>
```

{% endcode %}

Скорректируйте высоту и ширину формы.

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

<figure><img src="https://3019442075-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-M_eBlWEU4C3o2GVEAAr%2Fuploads%2F3LCpTfBCo55JKltHUF7d%2Fimage.png?alt=media&#x26;token=287b2ae9-c035-4364-ba94-6d50aa779ce6" alt=""><figcaption></figcaption></figure>

### Передача параметров на родительскую форму

По кнопке "Сохранить" мы должны передавать на родительскую форму наименование города, которое ввел пользователь. При этом дочерняя форма должна закрываться. Для передачи данных между форм используем параметры формы, описанные в тэге `<Parameters>`.

Создадим новый параметр:

{% code title="TemplateCityEdit.xml" %}

```markup
<Parameter Name="CityTitle" />
```

{% endcode %}

Добавим на форму команду типа [ValueSetCommand](https://wfsys.gitbook.io/workflow-forms-syntax/workflow_forms/commands/value_set_command), которая будет параметру **CityTitle** присваивать значение из текстового поля **TitleTextBox**:

{% code title="TemplateCityEdit.xml" %}

```markup
<Command Name="CityTitleValueSetCommand" Type="ValueSetCommand" Assembly="Commands">
  <Parameter Name="CityTitle">
    <Object Name="TitleTextBox" />
  </Parameter>
</Command>
```

{% endcode %}

В файле уже описана команда [FormCloseCommand](https://wfsys.gitbook.io/workflow-forms-syntax/workflow_forms/commands/form_close_command), которая будет закрывать окно. Нам нужно лишь объединить ее с нашей командой в одну последовательность [SequentialCommand](https://wfsys.gitbook.io/workflow-forms-syntax/workflow_forms/commands/sequential_command). Добавим следующий код в тэг `<Commands>`:

{% code title="TemplateCityEdit.xml" %}

```markup
<Command Name="SaveSequentialCommand" Type="SequentialCommand" Assembly="Commands">
  <Commands>
    <Command Name="CityTitleValueSetCommand" />
    <Command Name="FormCloseCommand" />
  </Commands>
</Command>
```

{% endcode %}

И затем на кнопке **SaveButton** пропишем вызов этой последовательности.

## Получение данных от дочерней формы

Перейдем в файл стартовой формы (TemplateStart.xml) и реализуем обработку результата выполнения команды **CityAddFormShowCommand**.

У таблицы [DatabaseTable](https://wfsys.gitbook.io/workflow-forms-syntax/workflow_forms/objects/databasetable) есть set-проперти [AddRow](https://wfsys.gitbook.io/workflow-forms-syntax/workflow_forms/objects/databasetable#set_add_row), [AddRows](https://wfsys.gitbook.io/workflow-forms-syntax/workflow_forms/objects/databasetable#set_add_rows), [UpdateRow](https://wfsys.gitbook.io/workflow-forms-syntax/workflow_forms/objects/databasetable#set_update_row), [UpdateRows](https://wfsys.gitbook.io/workflow-forms-syntax/workflow_forms/objects/databasetable#set_update_rows) и [DeleteRowsByIndices](https://wfsys.gitbook.io/workflow-forms-syntax/workflow_forms/objects/databasetable#set_delete_rows_by_indices). Они позволяют редактировать строки в таблице. Чтобы воспользоваться этими свойствами необходима команда [ValueSetCommand](https://wfsys.gitbook.io/workflow-forms-syntax/workflow_forms/commands/value_set_command).

{% hint style="info" %}
Ряд соединений с данными (например, [PrimaryGetDataConnection](https://wfsys.gitbook.io/workflow-forms-syntax/workflow_forms/dataconnections/primary_dc), [SecondaryGetDataConnection](https://wfsys.gitbook.io/workflow-forms-syntax/workflow_forms/dataconnections/secondary_dc) и [ConvertDataConnection](https://wfsys.gitbook.io/workflow-forms-syntax/workflow_forms/dataconnections/convert_dc)) так же обладают набором set-проперти (AddRow, AddRows, UpdateRow, UpdateRows и DeleteRowsByIndices) для редактирования своих записей.
{% endhint %}

Давайте создадим такую команду для добавления записи в таблицу:

{% code title="TemplateStart.xml" %}

```markup
<Command Name="CityDatabaseTableAddRowValueSetCommand" Type="ValueSetCommand" Assembly="Commands">
  <Object Name="CityDatabaseTable">
    <Property Name="AddRow">
      <Parameters>
        <Parameter Name="ColumnNames"> </Parameter>
        <Parameter Name="Values"> </Parameter>
        <Parameter Name="SelectAfterAdd"> </Parameter>
      </Parameters>
    </Property>
  </Object>
</Command>
```

{% endcode %}

Параметр **ColumnNames** ожидает линейный массив названий столбцов таблицы. Чтобы создать такой линейный массив используем структуру данных [Structure](https://wfsys.gitbook.io/workflow-forms-syntax/workflow_forms/values/structure) типа [List](https://wfsys.gitbook.io/workflow-forms-syntax/workflow_forms/values/structure#list). Т.к. дочерняя форма возвращает только наименование города, то в списке колонок будет лишь одно имя колонки с наименованием:

```markup
<Parameter Name="ColumnNames">
  <Structure Type="List">
    <Item>Title</Item>
  </Structure>
</Parameter>
```

Параметр **Values** так же ожидает линейный массив значений, которые будут добавляться в колонки, указанные в параметре **ColumnNames**. Нам нужно значение, которое мы сохранили в параметр формы **CityTitle**. К параметрам формы, которую открывали через команду FormShowCommand, можно обратиться через атрибут `Parameter` тэга `<Command>`:

```markup
<Parameter Name="Values">
  <Structure Type="List">
    <Item>
      <Command Name="CityAddFormShowCommand" Parameter="CityTitle" />
    </Item>
  </Structure>
</Parameter>
```

Параметр **SelectAfterAdd** определяет, будет ли выделена новая строка после ее добавления. Ожидает логическое значение. Присвоим ему значение **True**.

В итоге общий синтаксис команды будет иметь вид:

{% code title="TemplateStart.xml" %}

```markup
<Command Name="CityDatabaseTableAddRowValueSetCommand" Type="ValueSetCommand" Assembly="Commands">
  <Object Name="CityDatabaseTable">
    <Property Name="AddRow">
      <Parameters>
        <Parameter Name="ColumnNames">
          <Structure Type="List">
            <Item>Title</Item>
          </Structure>
        </Parameter>
        <Parameter Name="Values">
          <Structure Type="List">
            <Item>
              <Command Name="CityAddFormShowCommand" Parameter="CityTitle" />
            </Item>
          </Structure>
        </Parameter>
        <Parameter Name="SelectAfterAdd">True</Parameter>
      </Parameters>
    </Property>
  </Object>
</Command>
```

{% endcode %}

Теперь нужно на кнопке **CityAddButton** в тэге `<Commands>` добавить вызов этой команды сразу за вызовом команды **CityAddFormShowCommand**. Таким образом, синтаксис кнопки добавления записи в таблицу будет выглядеть так:

{% code title="TemplateStart.xml" %}

```markup
<MyObject Name="CityAddButton" Type="Button" Assembly="BaseControls">
  <Top>
    <Object Name="CityDatabaseTable">
      <Property Name="Top" />
    </Object>
  </Top>
  <Left>
    <Calculate>
      <Expression>{0} + 5</Expression>
      <Items>
        <Item>
          <Object Name="CityDatabaseTable">
            <Property Name="Right" />
          </Object>
        </Item>
      </Items>
    </Calculate>
  </Left>
  <Width>40</Width>
  <Height>40</Height>
  <Hint>Добавить запись...</Hint>
  <BackgroundImage>Images\24x24\plus.png</BackgroundImage>
  <BackgroundImageLayout>Center</BackgroundImageLayout>
  <FlatStyle>Flat</FlatStyle>
  <FlatBorderSize>1</FlatBorderSize>
  <FlatBorderColor>ButtonFlatBorderColor</FlatBorderColor>
  <FlatMouseDownBackColor>ButtonFlatMouseDownBackColor</FlatMouseDownBackColor>
  <FlatMouseOverBackColor>ButtonFlatMouseOverBackColor</FlatMouseOverBackColor>
  <Commands>
    <Command Name="CityAddFormShowCommand" />
    <Command Name="CityDatabaseTableAddRowValueSetCommand" />
  </Commands>
</MyObject>
```

{% endcode %}

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

## Сохранение изменений в таблицу в базе данных

### Запрос на вставку данных

Перейдем в файл серверной xml (Template.xml). И добавим запрос на вставку данных в таблицу **template.city** в базе данных:

{% code title="Template.xml" %}

```markup
<SqlQuery Name="CityInsertSqlQuery">
  <Text>
    INSERT INTO template.city (
      title
    )
    VALUES (
      {Title}
    );
  </Text>
</SqlQuery>
```

{% endcode %}

Этот запрос будет использоваться на форме в соединении с данными для отправки [DatabaseTableSetDataConnection](https://wfsys.gitbook.io/workflow-forms-syntax/workflow_forms/dataconnections/database_table_set_dc), которое будет описано ниже.

{% hint style="info" %}
Обратите внимание, что параметры, передаваемые с формы, указываются в фигурных скобках, например, `{Title}`. Причем названия этих параметров должны совпадать с названиями параметров, указанных в DatabaseTableSetDataConnection.
{% endhint %}

Создадим новое разрешение для этого запроса. Т.к. разрешение связано с редактированием записей в таблице, то отметим этот момент в имени разрешения, указав после имени сущности "Edit":

{% code title="Template.xml" %}

```markup
<Permission Name="CityEditSqlQueryPermission" Type="SqlQueryPermission">
  <SqlQueries>
    <SqlQuery Name="CityInsertSqlQuery" />
  </SqlQueries>
</Permission>
```

{% endcode %}

После чего создадим новую роль для редактирования городов. И дополнительно этой роли выдадим разрешение на получение списка городов. Тем самым предоставив роли полный набор прав для возможности редактирования списка.

{% code title="Template.xml" %}

```markup
<Role Name="CityEditRole">
  <Permissions>
    <Permission Name="CityViewSqlQueryPermission" />
    <Permission Name="CityEditSqlQueryPermission" />
  </Permissions>
</Role>
```

{% endcode %}

Затем у группы **GuestGroup** заменим роль:

{% code title="Template.xml" %}

```markup
<Group Name="GuestGroup">
  <Roles>
    <Role Name="CityEditRole" />
  </Roles>
</Group>
```

{% endcode %}

### Отправка данных на сервер

Перейдем в файл описания стартовой формы (TemplateStart.xml).

Реализация отправки данных делится на два этапа:

* описание соединения с данными для отправки: [SetDataConnection](https://wfsys.gitbook.io/workflow-forms-syntax/workflow_forms/dataconnections/set_dc) или [DatabaseTableSetDataConnection](https://wfsys.gitbook.io/workflow-forms-syntax/workflow_forms/dataconnections/database_table_set_dc);
* описание и вызов команды, которая будет обращаться к соединению с данными для отправки: [SaveCommand](https://wfsys.gitbook.io/workflow-forms-syntax/workflow_forms/commands/save_command).

{% hint style="info" %}
Загрузка данных через соединение с данными для загрузки ([PrimaryGetDataConnection](https://wfsys.gitbook.io/workflow-forms-syntax/workflow_forms/dataconnections/primary_dc)) происходит автоматически при открытии формы, а соединения с данными для отправки ([SetDataConnection](https://wfsys.gitbook.io/workflow-forms-syntax/workflow_forms/dataconnections/set_dc) или [DatabaseTableSetDataConnection](https://wfsys.gitbook.io/workflow-forms-syntax/workflow_forms/dataconnections/database_table_set_dc)) выполнятся при вызове. Поэтому и нужна команда [SaveCommand](https://wfsys.gitbook.io/workflow-forms-syntax/workflow_forms/commands/save_command), которая будет обращаться к соединению с данными для отправки, чтобы последнее осуществило отправку.
{% endhint %}

#### Описание соединения с данными для отправки на сервер

Создадим сохраняющее соединение типа DatabaseTableSetDataConnection, которое напрямую из таблицы берет измененные строки и отправляет на сервер:

{% code title="TemplateStart.xml" %}

```markup
<DataConnection Name="CityDatabaseTableSetDataConnection" Type="DatabaseTableSetDataConnection" Assembly="ComplexDataConnections">
  <Workflow Name="Template" />
  <DatabaseTable Name="" />
  <Parameters>
    <Parameter NativeName="">
      <Column Name="" />
    </Parameter>
  </Parameters>
  <SqlQueries>
    <SqlQuery Name="" Type="" />
  </SqlQueries>
</DataConnection>
```

{% endcode %}

Тэг `<Workflow>` описывает имя процесса, в рамках которого происходит запрос.

В тэге `<DatabaseTable>` в атрибуте `Name` ожидается имя таблицы, описанной на форме. Для этой таблицы и будет происходит сохранение изменений. Укажем в этом тэге имя нашей таблицы:

```markup
<DatabaseTable Name="CityDatabaseTable" />
```

Тэг `<Parameters>` содержит список параметров, передаваемых в запросы. Каждый параметр представлен тэгом `<Parameter>`. Имя параметра, указанное в атрибуте `NativeName`, должно полностью совпадать с именем параметра, указанного в фигурных скобках в тексте SQL-запроса. В качестве значения тэга указывается колонка сохраняемой таблицы, из которой будут подставляться значения в соответствующий параметр запроса.

```markup
<Parameter NativeName="Title">
  <Column Name="Title" />
</Parameter>
```

{% hint style="info" %}
Так же в качестве значения тэга `<Parameter>` можно указать любое универсальное значение: любой объект формы, значение условия, результат команды, параметр формы и другое. Полное описание универсальных значений можно прочитать по [ссылке](https://wfsys.gitbook.io/workflow-forms-syntax/workflow_forms/values).
{% endhint %}

В тэге `<SqlQueries>` описываются запросы для отправки данных. В атрибуте `Name` тэга `<SqlQuery>` указывается имя запроса, описанного в серверном файле. В качестве значения атрибута `Type` ожидается значение **Insert**, **Update** или **Delete**. В insert-запросы передаются параметры новых строк таблицы, в update-запросы - измененных строк, в delete-запросы - удаленных строк. DatabaseTable сразу разделяет свои строки по соответствующим коллекциям. Потому DatabaseTableSetDataConnection знает для каких строк таблицы какой запрос использовать.

В серверном XML-файле ранее описали запрос на вставку новых данных в таблицу базы данных - **CityInsertSqlQuery**. Укажем его в соединении с данными:

```markup
<SqlQueries>
  <SqlQuery Name="CityInsertSqlQuery" Type="Insert" />
</SqlQueries>
```

Таким образом, общий синтаксис соединения с данными для отправки будет выглядеть так:

{% code title="TemplateStart.xml" %}

```markup
<DataConnection Name="CityDatabaseTableSetDataConnection" Type="DatabaseTableSetDataConnection" Assembly="ComplexDataConnections">
  <Workflow Name="Template" />
  <DatabaseTable Name="CityDatabaseTable" />
  <Parameters>
    <Parameter NativeName="Title">
      <Column Name="Title" />
    </Parameter>
  </Parameters>
  <SqlQueries>
    <SqlQuery Name="CityInsertSqlQuery" Type="Insert" />
  </SqlQueries>
</DataConnection>
```

{% endcode %}

#### Команда для отправки данных на сервер

Как было сказано выше, для отправки данных на сервер используется команда типа [SaveCommand](https://wfsys.gitbook.io/workflow-forms-syntax/workflow_forms/commands/save_command). Создадим такую команду в тэге `<Commands>` и укажем в ней описанное ранее соединение с данными:

{% code title="TemplateStart.xml" %}

```markup
<Command Name="CityDatabaseTableSaveCommand" Type="SaveCommand" Assembly="Commands">
  <DataConnections>
    <DataConnection Name="CityDatabaseTableSetDataConnection" />
  </DataConnections>
</Command>
```

{% endcode %}

А теперь вызов этой команды следует разместить в описании кнопки сохранения **SaveButton** в тэге `<Commands>`. Таким образом, общий синтаксис кнопки сохранения изменений на форме в таблицу city в базе данных будет выглядеть так:

{% code title="TemplateStart.xml" %}

```markup
<MyObject Name="SaveButton" Type="Button" Assembly="BaseControls">
  <Top>5</Top>
  <Right>
    <Formula>
      <Minus DataType="IntegerDataType">
        <Item>
          <Object Name="FootPanel">
            <Property Name="Right" />
          </Object>
        </Item>
        <Item>5</Item>
      </Minus>
    </Formula>
  </Right>
  <Height>30</Height>
  <Width>200</Width>
  <TextAlign>MiddleCenter</TextAlign>
  <FontStyle>ButtonFontStyle</FontStyle>
  <ImageAlign>MiddleLeft</ImageAlign>
  <Image>Images\24x24\content-save.png</Image>
  <FlatStyle>Flat</FlatStyle>
  <FlatBorderSize>1</FlatBorderSize>
  <FlatBorderColor>ButtonFlatBorderColor</FlatBorderColor>
  <FlatMouseDownBackColor>ButtonFlatMouseDownBackColor</FlatMouseDownBackColor>
  <FlatMouseOverBackColor>ButtonFlatMouseOverBackColor</FlatMouseOverBackColor>
  <Text>Сохранить</Text>
  <Commands>
    <Command Name="CityDatabaseTableSaveCommand" />
  </Commands>
</MyObject>
```

{% endcode %}

Перезапустите проект. Убедитесь, что формы успешно загружаются, а изменения корректно сохраняются в базе данных.

<figure><img src="https://3019442075-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-M_eBlWEU4C3o2GVEAAr%2Fuploads%2FhmQxv8QjzQ4LMYJXtz2S%2Fimage.png?alt=media&#x26;token=83fc2d21-5190-4f39-a773-b45bc6fa5606" alt=""><figcaption></figcaption></figure>

## Итоги <a href="#results" id="results"></a>

Как вы могли заметить, на данный момент есть несколько недочетов:

* При закрытии карточки города по крестику (без сохранения), в таблицу добавляются пустые строки. Происходит лишнее срабатывание команды CityDatabaseTableAddRowValueSetCommand;
* Нет проверки корректности заполнения текстового поля "Наименование".

Эти недочеты мы поправим в последующих уроках.&#x20;

А пока подведем итог того, что мы узнали:

* для загрузки данных из базы данных используем PrimaryGetDataConnection, который выполняется автоматически;
* для сохранения данных из таблицы на форме в таблицу в базе данных используем DatabaseTableSetDataConnection. Для его выполнения нужно использовать команду SaveCommand;
* как подключать и использовать паттерны форм;
* как на родительской форме получать данные с дочерней формы;
* как в таблицу на форме добавлять новые строки.

На следующем уроке мы:

* добавим возможность редактировать и удалять записи в таблице на форме;
* узнаем, как избежать лишнего срабатывания команд при работе с дочерними формами.

## Ответы <a href="#answer" id="answer"></a>

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

{% file src="<https://3019442075-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-M_eBlWEU4C3o2GVEAAr%2Fuploads%2F62CtTqHQbVTlWcC91ad1%2Flesson1-answer.zip?alt=media&token=3d0546a2-b985-418b-9a69-15b49b5d0677>" %}
