Управление таблицей внешней базы данных SQL

При инсталляции SberMobile в среде сложной ИТ-инфраструктуры предприятия необходимо управлять и использовать данные, хранимые во внешней базе данных. Этот урок показывает, как подключиться к внешей базе данных SQL и создать пользовательский интерфейс для поиска, фильтрации, создания, редактирования и удаления записей.

В этом уроке мы будем управлять внешней базой данных MySQL, содержащей данные RFID карт. Эту базу данных карт можно использовать для авторизации пользователей через различные устройства контроля доступа на базе RFID. Авторизация может также осуществляться через SberMobile, но описание этой функции не входит в задачи данного урока.

1. Подключение к внешней базе данных

Подключение к внешней базе данных MySQL будет осуществляться через драйвер устройства базы данных SQL SberMobile, который также может подключаться к любому другому типу базы данных через JDBC.

Вот как выглядит структура базы данных (снимок утилиты управления сторонней базой данных):

Вот данные (снимок утилиты управления сторонней базой данных):

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

Как только подключено устройство базы данных, становится доступна функция устройства Выполнить запрос. Эта функция позволяет выполнить произвольный запрос выбрать/обновить с пользовательскими параметрами, что критически необходимо для нашего случая.

Подключенная учетная запись устройства базы данных:

В нашем примере учетная запись устройства базы данных называется cardsDatabase, его путь контекста - users.admin.devices.cardsDatabase.

2. Дизайн поиска данных и управление пользовательским интерфейсом

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

Вот как выглядит форма управления картами:

Основные элементы пользовательского интерфейса включают:

  • Панель Топ Поиск с двумя текстовыми полями (идентификатор карты и имя держателя карты) и кнопка Поиск
  • Панель Нижние Карты с Редактором таблиц данных для просмотра/редактирования карт и кнопка Сохранение изменений

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

3. Привязка интерфейса к базе данных

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

У нашего виджета есть только две привязки.

Кнопка поиска привязок

Первая привязка работает при щелчке по кнопке Поиск (как указано активатором form/searchButton:click@):

Цель

form/cards:dataTable

Выражение

addColumns(adjustRecordLimits(callFunction("users.admin.devices.cardsDatabase", "executeQuery", "select * from cards where id like ? and name like ?", false, table("<<cardId><S>><<cardholderName><S>>", "%" + {form/cardId:text} + "%", "%" + {form/cardholderName:text} + "%")), 0, 1000000000), "<originalId><S>", "{id}")

Активатор

form/searchButton:click@

Условие


Опции

On Event

Привязка загружает данные карты путем вызова функции executeQuery из устройства Базы данных SQL (указанного путем контекста users.admin.devices.cardsDatabase) и помещает их в таблицу cards  (как указано целью form/cards:dataTable).

Текст запроса - select * from cards where id like ? and name like ?. Второй параметр false функции выполнения запроса говорит о том, что мы выполняем запрос выбора (не обновления). Третий параметр - это таблица в две колонки, сформированная "на лету" при помощи функции table(). Имя ее поля (cardId и cardholderName игнорируются, поскольку значение первой колонки используется для замещения первого параметра ? в тексте запроса и т.д.).

Конструкция "%" + {form/cardId:text} + "%" добавляет к началу и концу строки поиска символ %, чтобы активировать нестрогое соответствие для SQL-оператора like .

adjustRecordLimits(table, 0, 1000000000) расширяет минимальное и максимальное количество записей для таблицы, возвращенной запросом, чтобы позволить операторам удалять записи из таблицы карт и добавлять к ней новые записи.

И, наконец, addColumns(table, "<originalId><S>", "{id}") добавляет к таблице невидимую колонку originalId и задает ее значения, равные значениям в колонке id. Скрытая колонка позволит обновлять записи базы данных, даже если были отредактированы идентификаторы карт.

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

Привязка кнопки записи

Пивязка кнопки записи проста. Она выполняет функцию processChanges() в компоненте Редактор таблицы данных. См. в документации Обработка Функции Изменений для получения более подробной информации.

Свойства привязки:

Цель

form/cards:processChanges()

Выражение


Активатор

form/saveButton:click@

Условие


Опции

On Event

4. Конфигурирование обработки записей добавлено/изменено/удалено

Функция Изменение Процесса Редактора Таблиц Данных просматривает списки добавленных, измененных и удаленных записей и оценки специального выражения для каждой такой записи.

Таким образом, необходимо сконфигурировать три свойства нашего компонента Редактор Таблиц Данных Виджета (таблица Карты):

  • Выражение обработки добавленных записей
  • Выражение обработки измененных записей
  • Выражение обработки удаленных записей

Обработка добавленных записей

Вот Выражение обработки добавленных записей нашего виджета:

cell(callFunction("users.admin.devices.cardsDatabase", "executeQuery", "insert into cards (ID, Name, Active) values (?,?,?)", true, dt()), "rows") > 0

Это выражение вызывает ту же функцию executeQuery. Однако текст запроса другой: insert into cards (ID, Name, Active) values (?,?,?)

Второй параметр true функции executeQuery говорит о том, что мы пытаемся обновить запрос.

Третий параметр - это данные добавленной записи, "завернутые" в таблицу с одной строкой и указанные функцией dt() (поскольку это таблица по умолчанию во время расчета Выражения обработки добавленных записей).

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

Конструкция cell(executeQueryResult, "rows") > 0 гарантирует, что хотя бы одна запись была вставлена запросом. Обрабатываемая в данный момент запись удаляется из списка добавленных записей в этом случае.

Обработка удаленных записей

Вот Выражение обработки удаленных записей:

cell(callFunction("users.admin.devices.cardsDatabase", "executeQuery", "delete from cards where ID = ?", true, dt()), "rows") > 0

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

Обработка обновленных карт

Выражение обработки измененных записей несколько более сложное:

cell(callFunction("users.admin.devices.cardsDatabase", "executeQuery", "update cards set id = ?, name = ?, active = ? where id = ?", true, dt()), "rows") > 0 ? set(dt(), "originalId", 0, {id}) : false

Его первая часть отправляет обновленный запрос в базу данных, используя значение четвертого поля originalId как ключ для сравнения. Это необходимо, потому что первое видимое поле идентификатора карты может редактироваться операторами и все же должно будет точно соответствовать записям.

Часть set(dt(), "originalId", 0, {id}) рассчитывается, только если хотя бы одна запись обновляется. В этом случае мы берем потенциально оновленное значение поля id и снова сохраняем его в поле originalId, чтобы можно было дальше менять записи.

Заключение

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