Создание десктопного приложения на ObjectPascal+FireDAC и СУБД РЕД База Данных
Почему Delphi?
Несмотря на скептическое отношение у отечественных разработчиков в массе, среда разработки Delphi вовсе не умерла и продолжает пользоваться популярностью на международной арене.
Популярность методологии RAD (Rapid Application Development) не уменьшается, свидетельствуют отраслевые обзоры. Она позволяет организациям быстро создавать интерактивные приложения для удовлетворения развивающихся потребностей бизнеса.
Отмечены некоторые причины роста популярности RAD:
- Ускоренное время выхода на рынок. С помощью RAD можно быстро разрабатывать и внедрять приложения, что позволяет компаниям использовать новые возможности и адаптироваться к меняющимся условиям ведения бизнеса. Возрастающая важность быстрой разработки приложений в постпандемическом ландшафте
- Снижение затрат. Оптимизированный процесс разработки, связанный с методологией RAD, снижает общую стоимость разработки приложений.
- Лучший пользовательский опыт. RAD предполагает тесное сотрудничество между разработчиками и конечными пользователями, что позволяет командам разрабатывать приложения, которые обеспечивают более удовлетворительный и приятный пользовательский опыт.
- Более простое обслуживание и масштабируемость. Приложения, разработанные с использованием RAD, можно легко обновлять и масштабировать для удовлетворения растущих потребностей и ожиданий клиентов.
Delphi / RAD Studio компании Embarcadero позволяют создавать кросс-платформенные приложения на базе единого кода, и в сочетании с СУБД Firebird, особенно популярны на латиноамериканском континенте, в частности в Бразилии.
Давайте посмотрим, как быстро создать практическое приложение на Delphi для ведения телефонного справочника, используя российскую СУБД РЕД База Данных. Будет рассмотрен процесс создания приложений для СУБД РЕД База Данных с использованием компонентов доступа FireDAC и среды разработки IDE Delphi 12 Athens
Настройка среды и FireDAC
Начиная с версии RAD Studio XE3, библиотека FireDAC входит в обычный состав поставки и является стандартным набором компонент для работы с базами данных
К сведению FireDAC создан на основе библиотеки российского программиста Дмитрия Арефьева
Библиотека пришла на замену устаревшим технологиям доступа типа BDE и другим, предоставляет универсальный способ доступа к более, чем 20 различных типов СУБД (не считая версий) - как SQL, так и NoSql. Библиотека позволяет добиться повышения эффективности работы приложения с БД за счет использования особенностей и тонких настроек соединений с каждой из поддерживаемых СУБД. Для работы требуется установить клиентские библиотеки/драйвера от вендора используемой СУБД.
Для реализации этого приложения требуется настроить Delphi и FireDAC для работы с РЕД База Данных.
Изначально в FireDAC не была заложена работа с РЕД База Данных, но зато имеется полная поддержка FireBird - ближайшей “родственницы” РЕД Базы Данных. Настолько близкой, что даже имена клиентских библиотек у них совпадают: fbclient.dll
Доступ приложений к базе данных через FireDAC возможен в двух вариантах:
- в design-time – из интегрированной среды разработки во время создания и отладки приложения
- в run-time, когда скомпилированное и собранное приложение запускается вне среды разработки и обращается к БД напрямую. Фактически, это вариант промышленной эксплуатации приложения.
Отличия заключаются в размерности (битности) приложения и требуемых клиентских библиотек. IDE Delphi 12 - интегрированная среда разработки - пока является 32-битным приложением, для доступа к БД в ней требуются 32-битные DLL. Но само приложение может быть скомпилировано в 32- или 64-битные модули, для которых потребуются DLL соответствующей размерности.
К счастью, в дистрибутив РЕД Базы Данных включены оба варианта клиентских модулей DLL.
При стандартной установке отмеченные зеленым 64-битные файлы помещаются в общедоступные системные каталоги, а содержимое каталога WOW64 (отмечен красным) помещается в системный WOW64, который содержит 32-битные версии.
При стандартной установке клиентских файлов библиотек дополнительная настройка не требуется.
Как быть, если в системных каталогах уже есть DLL с такими же именами, например от установленного на этот же компьютер экземпляра FireBird? Можно поступить так:
-
скопировать указанные файлы в какой-либо каталог на локальном диске, например, в /dlls/RB
C:./RB | fbclient.dll # 64-bit | \---win32 FBCLIENT.DLL # 32-bit -
отредактировать файл настроек драйверов FDDrivers.ini. Обычно, он находится по адресу
%public%\Documents\embarcadero\studio\FireDAC
В этот файл нужно внести строки:
[FDDrivers.ini]
Encoding=UTF8
[RB]
BaseDriverID=FB
VendorLib=c:\dlls\RB\win32\fbclient.dll
[RBASE64]
BaseDriverID=FB
VendorLib=c:\dlls\RB\fbclient.dll
Строки
[RB]
BaseDriverID=FB
VendorLib=c:\dlls\RB\win32\fbclient.dll
создают виртуальный драйвер RB на основе драйвера FB, с подстановкой требуемой клиентской DLL. После сохранения отредактированного файла настройки станут активны после перезапуска Delphi.
Этот способ позволяет работать с датасетами РЕД Базы Данных прямо в IDE, в ветке FireDAC в окне Data Explorer, однако не слишком удобен при окончательном деплойменте приложения.
Еще один способ указания драйвера будет рассмотрен далее.
Создание базы данных PHONES и проверка соединения с ней
Для примера будем создавать приложение, аналогичное по функционалу Контактам в мобильном телефоне. Пользователь сможет вести список своих контактов, добавлять новых, редактировать данные контакта, удалять ненужные записи. Для каждой записи контакта можно будет добавить много номеров телефонов или адресов электронной почты, относящихся к этому абоненту. При удалении записи абонента все относящиеся к нему номера и адреса должны быть также удалены. Чтобы не перегружать пример лишними деталями, ограничимся максимально простым UI без особых украшений.
Для разработки приложения “Контакты” необходима база данных PHONES со структурой данных:

Для создания базы данных можно использовать как утилиту командной строки isql, входящую в комплект поставки сервера базы данных, так и любую программу с графическим интерфейсом, например, RDB Expert.
Можно воспользоваться утилитой isql:
- запускаем CMD (предполагается, что во время установки РЕД Базы Данных пароль SYSDBA был оставлен по умолчанию). Соединяемся с сервером, пример:
>isql
Use CONNECT or CREATE DATABASE to specify a database
SQL> CREATE DATABASE 'redbase/3050:C:\_data\PHONES.FDB' page_size 8192
CON> user 'SYSDBA' password 'masterkey';
SQL>
Теперь надо выполнить скрипт создания таблиц в этой базе данных с указанной выше схемой.
/* Setting properties */
SET NAMES NONE;
SET SQL DIALECT 3;
CONNECT 'redbase/3050:C:/_data/PHONES.FDB' USER 'SYSDBA' PASSWORD 'masterkey';
SET AUTODDL ON;
/* ----- Creating Tables ----- */
/* ABONENT */
CREATE TABLE ABONENT (
AB_ID INTEGER GENERATED BY DEFAULT AS IDENTITY NOT NULL,
AB_NAME VARCHAR(64),
AB_SURNAME VARCHAR(64),
AB_ADDRESS VARCHAR(256));
/* PHONENUM */
CREATE TABLE PHONENUM (
ENTRY VARCHAR(32) NOT NULL,
NUMBER NUMERIC(10),
DESCRIPTION VARCHAR(64),
PH_AB_ID INTEGER NOT NULL);
/* ----- PRIMARY KEYs defining ----- */
/* ABONENT.PK_AB */
ALTER TABLE ABONENT
ADD CONSTRAINT PK_AB PRIMARY KEY (AB_ID);
/* PHONENUM.PK_PHONENUM */
ALTER TABLE PHONENUM
ADD CONSTRAINT PK_PHONENUM PRIMARY KEY (ENTRY, PH_AB_ID);
/* ----- FOREIGN KEYs defining ----- */
/* PHONENUM.FK_AB */
ALTER TABLE PHONENUM
ADD CONSTRAINT FK_AB FOREIGN KEY (PH_AB_ID) REFERENCES ABONENT (AB_ID);
Заполняем таблицы тестовыми данными (при желании можно выполнить вставку большего числа тестовых записей)
SQL>INSERT INTO ABONENT (AB_NAME,AB_SURNAME,AB_ADDRESS) VALUES ('John','Doе','nearby');
SQL>Commit;
SQL>INSERT INTO PHONENUM (ENTRY,NUMBER,DESCRIPTION, PH_AB_ID) VALUES ('+7(495)1234567',74951234567,'MSK',2);
SQL>INSERT INTO PHONENUM (ENTRY,NUMBER,DESCRIPTION, PH_AB_ID) VALUES ('+7(812)1234567','Spb',2);
SQL>COMMIT;
SQL>select * from ABONENT;
...
SQL>select NUMBER,DESCRIPTION,PH_AB_ID from PHONENUM;
NUMBER DESCRIPTION PH_AB_ID
===================== ===================== ============
79166247001 <null> 1
74951234567 MSK 2
78121234567 Spb 2
SQL>EXIT;
Теперь можно выйти из isql и запустить Delphi
Разработка приложения “Контакты (Телефонный справочник)”
Главная форма
Запустить Delphi В главном меню выбрать
File > New > Windows VCL Application - Delphi
Результат:

Сохранить проект и главную форму в каталог на диске.
File > Save Project As…
Сначала сохраняется модуль главной формы. Выбрать каталог на диске и имя файла. Например:
- каталог: C:\Users\User\Documents\Embarcadero\Studio\Projects\ContactsSample
- имя файла главной формы: uMain.pas
- имя проекта; ContactSample.dproj
В панели Object Inspector изменить свойства формы: - Name: frmMain
- Caption: Контакты
Самый быстрый способ найти нужный компонент - нажать F6 и набрать начальные буквы для поиска:
Выделить нужную строку и нажать Enter - компонент будет помещен на форму.
Добавить на форму компоненты:
- TPanel – в Object Inspector изменить свойства:
- Name: Panel1
- Align: alTop
- Caption:
- TButton
- Name: btConnect
- Caption: - оставим по умолчанию (совпадает с Name) для наглядности
- Убедиться, что Button лежит на панели и является веткой Panel1 в дереве на панели Structure
- TDBNavigator положить на главную форму
- Align: alTop
- Остальное пока по умолчанию
- TDBGrid
- Name: DBGrid1
- Align: alTop
- TDBNavigator положить на главную форму
- Align: alBottom
- Name: DBNavigator2
- Остальное пока по умолчанию
- TDBGrid
- Name: DBGrid2
- Align: alClient
Должно получиться что-то вроде такого:

Datamodule - форма модели
Для доступа к базе данных нужно использовать компоненты библиотеки FireDAC. Можно положить их прямо на главную форму, но это не будет являться правильным подходом. Для того чтобы избежать сильной связанности модулей представления пользователя и доступа к СУБД, создайте новый модуль данных (data module) из меню Delphi:
File > New > Data Module - Delphi
Поместить на нее компоненты (проще всего в указанной последовательности, хотя это не критично). Задайте в Object Inspector указанные значения свойств для каждого:
- TFDConnection – для управления соединения с БД
- TFDQuery – для работы с таблицей ABONENTS
- Name = FDQuery1
- Connection = FDConnection1
- SQL = "select * from ABONENT;”
- TDatasource – для связи ABONENTS с элементами GUI на главной форме
- Dataset = FDQuery1
- TFDQuery – для работы с номерами телефонов и адресами абонентов
- Name = FDQuery2
- Connection = FDConnection1
- SQL = “select * from PHONENUM where PH_AB_ID = :AB_ID”
- TDatasource – для связи PHONENUM с элементами GUI на главной форме
- Dataset = FDQuery2
Сначала настроим FDConnection1. Нужно выделить этот компонент и нажать правую кнопку мыши для вызова меню. В меню выбрать Connection Editor Заполнить поля нужно как показано на рисунке

Тип СУБД указывается в поле Driver ID. Для настройки и проверки использован драйвер типа FB В поле Database указан путь на диске на сервере к файлу БД. Укажите свой актуальный. Для примера выбран пользователь SYSDBA и его пароль по умолчанию. В реальном приложении - должна происходить авторизация пользователя с соответствующими ролью и правами доступа к БД. Указано, что коммуникации с сервером будут идти по протоколу TCP\/IP. Для режима Embedded поле Protocol должно быть пустым. В поле Server нужно указать адрес сервера или его псевдоним, в поле Port - коммуникационный порт сервера, SQLDialect, используемый в БД, оставить равным 3. Указан CharacterSet = UTF8 для корректной работы с русскими именами и текстами.
Теперь можно нажать кнопку Test. При условии, что сервер запущен и доступен, при правильных настройках должно получиться
Connection established successfully
или будет выдана произошедшая ошибка доступа, с которой нужно разобраться.
Теперь требуется настройка первого запроса FDQuery1. Нужно мышью выделить компонент на форме и из меню правой клавиши выбрать Query Editor. Текст запроса должен выглядеть так, как на картинке. Можно (но не обязательно) проверить, как он работает (кнопка Execute), и увидеть результат. Так как запрос не имеет параметров, дальнейшая настройка пока не требуется.
Аналогичным образом поступаем с запросом FDQuery2. SQL текст запроса содержит один параметр :AB_ID, поэтому нужно перейти на вкладку Parameters и задать такие значения:

Осталось только настроить поддержку отношения Master/Detail между ABONENT и PHONENUM. В Object Inspector для FDQuery2 необходимо установить следующие значения свойств:
- MasterSource = DataSource1 //проверить, что DataSource1 ссылается на FDQuery1
- MasterFields = AB_ID
- IndexFieldName = PH_AB_ID
FireDAC автоматически будет подставлять значение первичного ключа ABONENTS в параметр запроса FDQuery2.
Возвращаемся в IDE на закладку с главной формой. Теперь следует перейти в редактор кода главной формы. В IDE Delphi переключение между редактором формы и редактором кода выполняется нажатием клавиши F12 (или с помощью меню).
Необходимо добавить немного кода, чтобы программа заработала.
- дописать имя файла дата модуля dmRDB в конец строки uses раздела interface главной формы. После этого компоненты дата модуля будут доступны в главной форме.
- F12 - Переключиться в режим редактора форм на главной форме. На главной форме были размещены data aware компоненты, которые следует настроить для работы с дата модулем.
- Выделяем мышью на форме компонент и настраиваем значения свойств в Object Inspector:
- DBNavigator1
- DataSource = RDB.DataSource1
- DBGrid1
- DataSource = RDB.DataSource1
- DBGrid2
- DataSource = RDB.DataSource2
- DBNavigator2
- DataSource = RDB.DataSource2
Осталось только написать обработчик нажатия кнопки btConnect. Кнопка будет работать как переключатель: если БД закрыта, то открывать ее, если открыта - закрывать.
Сделать двойной клик по кнопке btConect на главной форме. IDE автоматически создаст процедуру-обработчик события нажатия и перейдет в редактор кода для ее редактирования. Код процедуры:
with RDB do begin
FDConnection1.Connected:= not FDConnection1.Connected;
FDQuery1.Active:=FDConnection1.Connected;
FDQuery2.Active:=FDConnection1.Connected;
end;
Это не лучшее решение. Ниже обработчик будет переписан.
После сохранения проекта на диск File > Save All или Ctrl-Shift-S можно компилировать и запускать приложение для тестирования.
Для запуска в режиме интерактивной отладки нажимают клавишу F9, для запуска без отладки - Ctrl-Shift-F9

Первые итоги
- Приложение Windows “Телефонный справочник” было создано “с нуля” инструментом RAD-разработки. На практике, такая разработка займет от 10 минут до получаса.
- Приложение было создано путем применения на форме различных компонент VCL, связывания их путем настройки значений их свойств и настройки GUI в режиме WYSIWYG. Потребовалось написать лишь 5 строк кода (но можно было и обойтись совсем без написания строк кода).
- Для доступа к данным в Design-time режиме была настроена среда IDE Delphi и компоненты доступа к БД РЕД База Данных / FireBird библиотеки FireDAC
- Приложение “умеет работать” с данными, связанными в отношении Master/Detail
- Созданный прототип уже может быть собран для нескольких платформ (Win32, Win64, Linux (При наличии библиотеки CrossVCL) путем простой перекомпиляции.
- Для простоты изложения вопросы читабельности кода и настройки визуальной привлекательности GUI были опущены.
Недостатки
Недостатков у проекта достаточно много и они существенные.
- Получившийся код не очень “чистый”. Функционал недостаточно хорошо отделен от пользовательского представления. Это может вызвать сложности при поддержке проекта и развитии функционала приложения.
- Настройки драйверов и доступа к БД жестко “вшиты” в программу, что лишает ее гибкости. Лучше считывать рабочие настройки при старте программы из файлов с параметрами.
- При возможном переносе данных на другую СУБД придется вносить изменения во все модули.
- В реализации операций Create, Read, Update, Delete (CRUD) целиком положились на то, как их реализуют компоненты FireDAC.
- Слабо продуманы вопросы одновременной работы с БД многих пользователей, что может привести к резкому замедлению ее работы и проблемам при масштабировании.
В следующем разделе эти вопросы будут рассмотрены подробнее и предложены их решения с учетом особенностей РЕД Базы Данных.
CRUD и управление транзакциями
В подавляющем большинстве приложения должны выполнять те или иные модификации в базе данных. Чаще всего это операции из набора CRUD (Create, Read, Update, Delete). В примере “Телефонный справочник” также участвуют все эти операции, только они вызываются неявно в компонентах FireDAC (что очень удобно и сильно упрощает работу программиста). Первоначально данные считываются с сервера компонентами FDQuery. Чтобы добавить нового абонента в справочник нужно нажать на кнопку “плюс” в верхнем DBNavigator1, а для списка его телефонов – плюс на нижнем навигаторе. Редактировать данные можно прямо в таблице (компонент DBGrid). Режим редактирования включается либо при нажатии кнопки “пирамидка” в соответствующем навигаторе, либо двойным нажатием на поле в таблице.
Эти компоненты выполняют операции в буфере в памяти; чтобы изменения попали на сервер нужно выполнить “фиксацию”. Пока в этом примере фиксацию автоматически выполняют компоненты FireDAC внутри себя, с настройками по умолчанию. Так как данные этого приложения находятся в отношении “один-ко-многим” (Master/Detail), для целостности данных необходимо, чтобы при добавлении или каскадном удалении записей из справочника абонентов на сервер попадали связанные изменения сразу в обеих таблицах или не попадали совсем.
Для СУБД РЕД База Данных и FireBird не рекомендуется полагаться на внутреннюю работу компонент. Это может не позволить работать с данными оптимальным образом, может привести к проблемам масштабируемости при большом количестве одновременно работающих пользователей, замедлению работы базы данных. В РЕД Базе Данных и FireBird выгоднее управлять транзакциями явно.
В FireDAC можно явно управлять запуском и завершением транзакции в компоненте TFDConnection или использовать специальный компонент TFDTransaction. В этих СУБД можно открывать в рамках одного соединения много разных транзакций.
Модифицированное приложение будет использовать одну транзакцию для чтения данных и вторую для внесения изменений на сервер. Чтобы не мешать другим пользователям, транзакция для изменений должна быть как можно короче и выполняться не слишком часто. В таких случаях в FireDAC применяется Кеширование изменений.
В примере использован режим централизованного кэширования обновлений — когда несколько наборов данных совместно используют один журнал изменений, а изменения располагаются в историческом порядке. Чтобы включить такой режим, необходимо положить один экземпляр компонента TFDSchemaAdapter, и у обоих наборов данных (FDQuery) указать его в свойстве SchemaAdapter. Компонент TFDSchemaAdapter служит центральным хранилищем для изменений записей в нескольких наборах данных.

Централизованные кэшированные обновления полезны в отношениях “master-detail”, где главный (“master”) набор данных распространяет изменения на каскадные наборы данных “detail”, включая значения полей с автоинкрементом. Чтобы включить это распространение для набора данных “detail”, нужно выполнить следующее:
- Поместить TFDSchemaAdapter на datamodule dmRDB. Оставить имя Name = FDSchemaAdapter1, данное по умолчанию.
- Установить свойство SchemaAdapter основного набора данных FDQuery1 на FDSchemaAdapter1 .
- Установить для свойства SchemaAdapter связанного набора данных FDQuery2 значение FDSchemaAdapter1 .
- Установить для связанного набора данных FDQuery2 значение свойства FetchOptions.DetailCascade = True .
Значения других свойств компонент:
FDConnection1 – компонент связи с СУБД. Внутри себя открывает транзакцию и скрытым от пользователя образом управляет ею.
- Params - параметры соединения были заполнены в начале примера, оставить прежними
- Transaction –компонент TFDTransaction, который будет использоваться в качестве умолчательного для выполнения различных операций TFDConnection. Если это свойство не назначено явно, TFDConnection создаст себе экземпляр TFDTransaction самостоятельно, его параметры можно указать в свойстве TxOptions. Оставить пустым. Попытаемся использовать встроенную транзакцию, но управлять ей явно.
- TxOptions - параметры работы со встроенной транзакцией.
- AutoCommit = False
- Isolation = xiReadCommited
- ReadOnly = True В РЕД База Данных такая транзакция стартует с параметрами read write concurrency wait; Поскольку эта транзакция используется только для чтения, наша транзакция будет иметь параметры read read_commited rec_version. Транзакция с такими параметрами в РЕД Базе Данных может быть открытой сколь угодно долгое время, без блокирования других транзакций или влияния на накопление мусора в базе данных.
Дополнительные свойства:
- Connected – управление подсоединением к БД, или проверка состояния соединения. Это свойство должно быть выставлено в True для работы мастеров других компонентов FireDac. Если ваше приложение должно запрашивать данные для авторизации, то важно не забыть сбросить это свойство в False перед компиляцией вашего приложения.
- LoginPrompt – запрашивать ли имя пользователя и пароль при попытке соединения.
- UpdateTransaction – компонент TFDTransaction, который будет использоваться в качестве рабочего для одноимённых свойств компонентов TFDQuery. Если это свойство не назначено явно, будет использовано значение из свойства Transaction.
Обращение к БД для внесения изменений будет происходить только в момент, когда будет явное требование пользователя сохранить накопленные кешированные изменения. Для этого надо добавить две дополнительные кнопки на главную форму: btCommit и btCancel.
и создать обработчики нажатия для каждой:
// RDB - это имя data module
// отменяет все не подтвержденные накопленные изменения данных
// затем перечитывает данные на экран
procedure TfrmMain.btCancelClick(Sender: TObject);
begin
RDB.CancelUpdates();
RDB.RefreshData(True);
end;
// Запускает фиксацию не подтвержденных изменений данных на сервере.
// Если не все записи были зафиксированы на сервере, сообщает об их количестве
// затем перечитывает данные на экран
procedure TfrmMain.btCommitClick(Sender: TObject);
begin
var iErr := RDB.ApplyUpdates();
if iErr <> 0 then
ShowMessage(format('%d ошибок',[iErr]));
RDB.RefreshData(True);
end;
Методы
RDB.CancelUpdates();
RDB.RefreshData(True);
RDB.ApplyUpdates();
должны быть созданы в data module dmRDB.pas
procedure TRDB.CancelUpdates;
begin
FDSchemaAdapter1.CancelUpdates;
end;
function TRDB.HasUpdates: boolean;
begin
Result := FDSchemaAdapter1.UpdatesPending;
end;
procedure TRDB.RefreshData(mode: boolean);
begin
FDConnection1.Connected := False;
if mode then
FDConnection1.Connected := True;
FDQuery1.Active:=FDConnection1.Connected;
FDQuery2.Active:=FDConnection1.Connected;
end;
Тем самым мы локализуем весь функционал работы с РЕД Базы Данных в одном модуле.
Следует обратить внимание на функцию, выполняющую реальные изменения и фиксацию их на сервере
function TRDB.ApplyUpdates: integer;
begin
// стартуем транзакцию
fdCachedTransation.StartTransaction;
// если в наборе данных есть изменения
Result := FDSchemaAdapter1.ApplyUpdates();
if Result = 0 then begin
// записываем их в БД
FDSchemaAdapter1.CommitUpdates;
// и подтверждаем транзакцию
fdCachedTransation.Commit;
end
else
// Если ошибки - откатываем транзакцию
if fdCachedTransation.Active then
fdCachedTransation.Rollback;
Пишущая транзакция fdCachedTransaction должна быть максимально короткой, и иметь режим изолированности SNAPSHOT.
Она использует компонент типа TFDTransaction для явного управления транзакцией внесения изменений на сервер с такими значениями свойств:
Options.AutoStart = False
Options.AutoCommit = False
Options.AutoStop = False
Options.DisconnectAction = xdRollback
Options.Isolations = xiSnapshot
Options.ReadOnly = False
Рефакторинг и гибкие настройки
Сначала локализуем всю ответственность по связи с БД в одном модуле. Принято инкапсулировать функционал в экземпляре специального класса. В примере таким классом может стать класс модуля данных (datamodule), который уже присутствует в проекте. В нем надо определить несколько методов, для выполнения требуемых операций с БД, а в главном модуле поместить ссылку на экземпляр этого класса, через который будут вызываться эти методы. Таким образом будет уменьшена связность и улучшена независимость модулей проекта. Если в проекте будет предусмотрена работа с разными типами СУБД, приложение создаст экземпляр именно того класса, который отвечает за работу с выбранным типом, а остальной код не потребует изменений.

- В опциях проекта
Project > Options...уберем форму c именем RDB из списка автоматически создаваемых объектов форм. - Все необходимые методы были уже перенесены в модуль данных, когда реализовывался режим кешированных обновлений.
- В главной форме добавляется переменная для хранения ссылки на экземпляр модуля данных и функция создания и инициализации этого экземпляра.
type
TfrmMain = class(TForm)
...
private
{ Private declarations }
Storage: TRDB;
function _GetRDBStorage(): TRDB;
...
В самом начале работы приложения, в данном случае в событии OnFormCreate главной формы эта функция будет вызвана и результат будет записан в эту переменную. Главная форма управляет циклом жизни экземпляра модуля данных и отвечает за его освобождение в событии OnFormClose при завершении работы приложения.
procedure TfrmMain.FormCreate(Sender: TObject);
begin
Storage := TRDB(_GetRDBStorage());
end;
procedure TfrmMain.FormClose(Sender: TObject; var Action: TCloseAction);
begin
Storage.Free;
end;
function TfrmMain._GetRDBStorage: TRDB;
begin
if RDB = nil then
RDB := TRDB.Create(Self);
Result:= RDB;
end;
Теперь все обращения к модулю должны идти с использованием сохраненной ссылки:
// отменяет все не подтвержденные накопленные изменения данных
// затем перечитывает данные на экран
procedure TfrmMain.btCancelClick(Sender: TObject);
begin
Storage.CancelUpdates();
Storage.RefreshData(True);
end;
// Запускает фиксацию не подтвержденных накопленные изменения данных на сервере.
// Если не все записи были зафиксированы на сервере, сообщает об их количестве
// затем перечитывает данные на экран
procedure TfrmMain.btCommitClick(Sender: TObject);
begin
var iErr := Storage.ApplyUpdates();
if iErr <> 0 then
ShowMessage(format('%d ошибок',[iErr]));
Storage.RefreshData(True);
end;
Настройки драйверов и доступа к БД жестко “вшиты” в программу, и это лишает ее гибкости при развертывании. Лучше считывать рабочие настройки при старте программы из файлов с параметрами. Для примера имя файла с настройками зашито в код в виде констант, так же как и имя секции, но на практике лучше получать их из командной строки при запуске приложения. В примере имя файла с настройками 'config.ini' и он должен быть расположен в том же каталоге, рядом с исполняемым модулем EXE.
Файл настроек может выглядеть примерно так:
[DBParams]
Database=c:\_data\PHONES.fdb
User_Name=SYSDBA
Password=masterkey
Protocol=TCPIP
Server=redbase
Port=3050
CharacterSet=UTF8
DriverID=FB
ClientLib=c:\data\dlls\fb\win32\fbclient.dll
хотя прописывать пароли в таком файле - опасная практика. Можно воспользоваться этим же файлом настроек, чтобы гибко задавать путь и имя клиентской библиотеки РЕД База Данных (параметр ClientLib). Это полезно в случае разных вариантов использования СУБД, например, embedded mode.
uses
System.IniFiles;
const
INIFILENAME = 'config.ini';
INISECTION = 'DBParams';
procedure TRDB.LoadParams(filename: string);
begin
// считываем параметры подключения
var hIniFile := TIniFile.Create(filename);
try
hIniFile.ReadSectionValues(INISECTION, FDConnection1.Params);
finally
hIniFile.Free;
end;
end;
Считывание настроек происходит сразу после создания экземпляра объекта.
procedure TRDB.DataModuleCreate(Sender: TObject);
begin
LoadParams(GetCurrentDir + PathDelim + INIFILENAME);
var conlib := FDConnection1.Params.values['ClientLib'];
if conlib <> '' then
FDPhysFBDriverLink1.VendorLib := conlib;
end;
Для простоты здесь не показан код для проверки ошибок при считывании настроек.
Итоги
Приложение Windows “Контакты (Телефонный справочник)” было создано “с нуля” инструментом RAD-разработки. На практике, такая разработка займет от 10 минут до получаса.
- Приложение было создано путем применения на форме различных компонент VCL, связывания их путем настройки значений их свойств и настройки GUI в режиме WYSIWYG.
- Для доступа к данным в режиме Design-time была настроена среда IDE Delphi и компоненты доступа к СУБД РЕД База Данных / FireBird библиотеки FireDAC
- Для простоты изложения вопросы читабельности кода и настройки визуальной привлекательности GUI были опущены.
- Приложение обрабатывает данные, связанные в отношении один-ко-многим (Master/Detail).
Применение отдельного модуля данных и использование механизмов ООП в Delphi позволило локализовать всю логику работы с СУБД и базой данных и отделить ее от пользовательского представления. Это упрощает поддержку приложения и дает задел на возможное применение другой СУБД в будущем.
В приложении были учтены и использованы особенности СУБД РЕД База Данных / FireBird. Явное управление транзакциями и уровнями изоляции обеспечивает более надежное и эффективное обращение с данными в приложении.
Был применен один из способов для реализации более гибкой системы настройки при запуске приложения. Это решает многие вопросы в случае передачи приложения заказчику.
Дата последнего изменения: 14.09.2026
Если вы нашли ошибку, пожалуйста, выделите текст и нажмите Ctrl+Enter.