Fibplus fib data set получить имя колонки

Devrace FIBPlus: Использование базы данных в качестве хранилища запросов и настроек клиентских приложений

Devrace FIBPlus: Использование базы данных в качестве хранилища запросов и настроек клиентских приложений

Рано или поздно большинство разработчиков приходят к тому, чтобы делать свои приложения как можно более простыми для определенных модификаций без требования перекомпиляции всей программы. Если это касается работы с базами данных, то, как правило, программисты начинают выносить запросы во внешние текстовые файлы или хотя бы сохраняют настройки пользовательского интерфейса во внешних файлах конфигурации. Этот подход, однако, имеет свой недостаток: при изменении настроек приходится копировать их на все рабочие места. Поэтому следующим этапом создания более гибких многопользовательских приложений является перенос подобных вещей в базу данных. Используя InterBase и Firebird при помощи FIBPlus, мы получаем в руки готовый механизм, называемый FIBPlus Repository.

Шаг первый: сохранение и использование визуальных настроек полей в базе данных.
Самое простое, что можно сделать при помощи FIBPlus Repository — это сохранить в базе данных такие настройки полей, как Display Label или Display Format, а потом автоматически получить эти настройки из базы данных в приложение без единой строчки дополнительного кода.

Разместим на форме следующие основные компоненты: pFIBDatabase1: TpFIBDatabase, pFIBDataSet: TpFIBDataSet, pFIB Transaction: TpFIBTransaction, DataSource1: TDataSource, DB Grid1: TDBGrid. Мы не будем останавливаться на очевидных деталях: указание параметров подключения к базе данных в pFIBDatabase1, связывание компонентов FIBPlus между собой, связывание DataSource1 и pFIBDataSet и т.д. Все эти моменты были неоднократно описаны в предыдущих статьях. Отметим только, что мы будем использовать для наших примеров стандартную базу данных Employee. gdb, которая поставляется вместе с Borland InterBase.
Укажем следующий запрос для pFIBDataSet1.SelectSQL:

И сгенерируем модифицирующие запросы (UpdateSQL, DeleteSQL и InsertSQL) при помощи SQL Generator, входящего в поставку FIBPlus. Этот вопрос тоже неоднократно освещался в статьях по FIBPlus. Запустим приложение:

Рис. 1. Внешний вид приложения без использования FIBPlus Repository

Как мы можем видеть, колонки в DBGrid1 называются так же, как и физические поля в базе данных. Очевидно, что это не очень удобно для пользователя, особенно если мы хотим использовать национальные слова в колонках, поскольку InterBase, несмотря на SQL Dialect 3, имеет проблемы с использованием национальных символов в названиях полей. Delphi (равно как и BCB) позволяет нам настраивать такое свойство полей, как Display-Label. Именно это свойство выводится в заголовки DBGrid1. При работе в design-time мы можем создать экземпляры полей, указать в Object Inspector значения DisplayLabel для каждого из них и получить в DBGrid1 названия колонок, которые уже будут более понятны пользователям. Однако если в процессе работы над приложением мы будем вынуждены изменить структуру базы данных, то нам придется проделывать почти всю эту работу заново: удалять в design-time старые поля в pFIBDataSet1, добавлять новые, снова указывать DisplayLabel и т.д. Мы уже не говорим о том, что если вам просто захочется переименовать одно из полей, то придется перекомпилировать приложение и заново раздавать его всем пользователям в сети. Простая операция потребует кучу совершенно тривиальной и ненужной работы!

Всего этого можно избежать. FIBPlus позволяет сохранять настройки полей в базе данных. Таким образом, когда вы исправите настройки прямо в базе, то все заново подключившиеся приложения автоматически применят их без изменения и грамма кода. Обратимся к конкретным шагам. Нажмите правой кнопкой мыши на компоненте pFIBDatabase1 и вызовите редактор полей FIBPlus Repository:

Рис. 2. Вызов редактора полей FIBPlus Repository

FIBPlus Repository создает в основной базе данных дополнительную таблицу, причем на создание такой таблицы требуется наше явное разрешение. Нажмите ОК в появившемся диалоге, чтобы разрешить FIBPlus создать дополнительную таблицу FIB$ FIELDS_INFO в нашей базе данных. После создания мы увидим диалог редактирования свойств полей:

Рис. 3. Редактор FIB$FIELDS_INFO

Видно, что FIBPlus Repository позволяет нам сохранять такие настройки полей, как Dis-playLabel, Visible, DisplayFor-mat, EditFormat, DisplayWidth. Особенное внимание следует обратить на колонку Triggered. Некоторые поля в таблицах, имеющие опцию NOT NULL, предназначены для автоматического заполнения при помощи триггеров базы данных. Компоненты FIBPlus при получении мета-данных для генерации модифицирующих запросов выставляют свойство Required у всех полей с опцией NOT NULL. Программа начинает требовать от пользователя безусловного указания значений таких полей до отправки запроса на сервер. Такое поведение оправдано во всех случаях, кроме некоторых конкретных ситуаций, когда разработчик точно знает: только триггер имеет право менять значения определенных полей. Чтобы не запутать вас, приведем пример. Предположим, у нас в таблице Employee есть два триггера, которые формируют значения поля HIRE_DATE таблицы Employee:

CREATE TABLE EMPLOYEE (
EMP_NO EMPNO NOT NULL,
FIRST_NAME FIRSTNAME NOT NULL,
LAST_NAME VARCHAR(35) NOT NULL,
PHONE_EXT VARCHAR(4) CHARACTER SET NONE,
HIRE_DATE DATE DEFAULT ‘NOW’ NOT NULL,
DEPT_NO DEPTNO NOT NULL,
JOB_CODE JOBCODE NOT NULL,
JOB_GRADE JOBGRADE NOT NULL,
JOB_COUNTRY COUNTRYNAME NOT NULL,
SALARY SALARY NOT NULL,
FULL_NAME COMPUTED BY (last_na-me || ‘, ‘ || first_name)
);

CREATE TRIGGER EMPLOYEE_NEW_ HIRE_DATE FOR EMPLOYEE
ACTIVE AFTER INSERT POSITION 0
AS
begin
new.hire_date = ‘NOW’;
end

CREATE TRIGGER EMPLOYEE_NEW_ HIRE_DATE_UPD FOR EMPLOYEE
ACTIVE AFTER UPDATE POSITION 0
AS
begin
new.hire_date = ‘NOW’;
end

Очевидно, что пользователю бессмысленно менять значения этого поля. Тем не менее, поскольку поле HIRE_DATE описано как NOT NULL, то наше приложение будет требовать от пользователя внести хоть какое-то значение. Мы можем избежать этого, если укажем в FIBPlus Repository, что данное поле обрабатывается триггером.
Вернемся к редактору полей FIBPlus Repository. По двойному щелчку на названии таблицы Employee в списке ее поля будут добавлены в Repository. Нам остается только указать нужные нам значения. Мы можем даже спрятать лишние поля, указав Visible равным 0:

Рис. 4. Редактирование свойств полей в FIBPlus Repository

Теперь необходимо включить опцию psApplyRepository в pFIBDataSet1.PrepareOptions и запустить наше приложение:

Рис. 5. Настройки полей из FIBPlus Repository применены к pFIBDataSet1

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

Шаг второй: дополнительные возможности FIBPlus Repository.
Иногда возникает нужда в каких-либо дополнительных настройках для полей таблиц. Особенность FIBPlus Reposi-tory состоит в том, что он позволяет легко оперировать с любыми дополнительными полями в FIB$FIELDS_INFO. Предположим, мы хотим хранить значения DisplayLabel на трех языках. Очевидно, что одного поля DISPLAY_LABEL нам не хватит. Добавим пару колонок:
ALTER TABLE FIB$FIELDS_INFO ADD GERMANY_LABEL VARCHAR(20);
ALTER TABLE FIB$FIELDS_INFO ADD RUSSIAN_LABEL VARCHAR(20);
Откроем редактор полей в FIBPlus Repository и укажем альтернативные названия для DisplayLabel на немецком и русском языках:

Рис. 6. Заполнение значений для DisplayLabel на немецком и русском

Добавим компонент Combo-Box1: TComboBox на форму, зададим свойство ComboBox1. Style равным csDropDownList и внесем три элемента в свойство Items:
English
German
Russian

Добавим также компонент DataSetsContainer1: TDataSets-Container. Укажем свойство Container у pFIBDataSet1 равным DataSetsContainer1. Подключим модуль pFIBDataInfo в список uses в нашем модуле:
implementation
uses pFIBDataInfo;
Напишем обработчик OnClick у ComboBox1:
procedure TForm1.ComboBox1Click (Sender: TObject);
begin
pFIBDataSet1.CloseOpen(false);
end;
Напишем также обработчик события OnDataSetEvent у DataSetsContainer1:
procedure TForm1.DataSetsContai-ner1DataSetEvent(DataSet: TDataSet;
Event: TKindDataSetEvent);
var I: integer;
Dl: string;
begin
if Event = deAfterOpen then
with DataSet do
for I := 0 to (FieldCount — 1) do begin
case ComboBox1.ItemIndex of
1 : Dl := GetOtherFieldInfo(Fields[I], ‘GERMAN_LABEL’);
2 : Dl := GetOtherFieldInfo(Fields[I], ‘RUS-SIAN_LABEL’);
else
Dl := GetOtherFieldInfo(Fields[I], ‘DISPLAY_LABEL’);
end;
if Dl <> » then Fields[I].DisplayLabel := Dl;
end;
end;

Функция GetOtherFieldInfo обращается к FIBPlus Reposito-ry и возвращает значение нужного нам параметра для указаного поля. В нашем примере мы передаем по очереди все поля нашего pFIBDa-taSet1 и запрашиваем либо параметр GERMAN_LABEL, либо параметр RUSSIAN_LA-BEL в зависимости от текущего языка, выбранного в Combo-Box1. Запустите приложение и попробуйте выбрать немецкий язык в списке ComboBox1. Вы увидите, как будут заменены заголовки у столбцов в DB Grid1. Очевидно, что данный механизм может быть легко применен и для многих других настроек таблиц, которые хочется хранить в базе данных. Использование TDataSetsCon-tainer продиктовано тем, что этот компонент позволяет сосредоточить код по обработке дополнительных полей в FIB$ FIELDS_INFO в одном месте приложения. Подключая любые другие экземпляры TpFIB DataSet к DataSetsContainer1, вы тем самым автоматически получите использование дополнительных языков во всем приложении.

Шаг третий: Query Repository.
Логичным продолжением идеи о хранении настроек приложения в базе данных становится мысль о хранении в этой же базе и запросов. Это позволило бы оптимизировать запросы, вводить в них дополнительные поля или условия без перекомпиляции приложений.
В FIBPlus уже реализован механизм хранения запросов в базе данных. Обратите внимание на свойство DataSet_Id у TpFIBDataSet:

Рис. 7. Свойство DataSet_Id у TpFIBDataSet

Вызовем редактор этого свойства. Хранение запросов потребует создания в основной базе данных еще одной системной таблицы — FIB$DATA-SETS_INFO. При первом вызове редактора свойства Data-Set_ID нам будет предложено создать ее. Нажмите кнопку OK, и вы увидите диалог:

Рис. 8. Диалог Query Repository в редакторе свойства Data Set_Id у TpFIBDataSet

В таблице слева мы можем добавить необходимое количество групп запросов для приложения. Группа запросов — это серия запросов для SelectSQL, UpdateSQL, Dele-teSQL, Insert SQL и Refresh SQL, объединенных под одним номером, указанным в поле DS_ID. Поле Description содержит текстовый комментарий, который поможет вам в дальнейшем разобраться в целях той или иной группы запросов. На рисунке 8 видно, что мы можем добавить группу с номером 1 и заполнить все запросы начиная с SelectSQL. Для данного примера мы перенесем туда те SQL-тексты, которые были сгенерированы на предыдущих этапах SQL Generator’ом.

Замечание: Обратите внимание на поля Key field и Generator. В предыдущих статьях мы уже описывали, как использовать автогенерацию модифицирующих запросов и автозаполнение ключевого поля значениями генератора при помощи свойства AutoUpdate-Options в TpFIBDataSet. Репозитарий запросов позволяет вам хранить и изменять нужные параметры для AutoUp-dateOptions в базе данных наряду с запросами.

При нажатии на OK текущий выбранный DS_ID будет присвоен свойству DataSet_ID у pFIBDataSet1. Теперь мы можем смело удалять значения свойств SelectSQL, UpdateSQL, DeleteSQL, InsertSQL и RefreshSQL у pFIBDataSet1, поскольку они в любом случае будут браться из базы данных. Запустите приложение, и вы увидите, что оно работает так же, как и раньше. Разница состоит лишь в том, что в нашем коде нет ни запросов, ни настроек полей — все данные берутся из FIBPlus Repository. Мы можем взять любое средство администрирования базы данных или воспользоваться редакторами FIBPlus Repository, встроенными в FIBPlus, изменить значения в таблицах в FIB$FIELDS_INFO и FIB$ DATASETS_INFO и перезапустить приложение без перекомпиляции. Также следует отметить, что SQL Generator автоматически начинает работать с использованием FIBPlus Reposi-tory, если значение свойства DataSet_ID у TpFIBDataSet отлично от нуля. Таким образом, вы имеете целый ряд возможностей работы с FIBPlus Repository. В любом случае новые запросы и настройки будут применяться в вашем приложении автоматически.

Например, мы можем захотеть показать дополнительную информацию о сотрудниках — их должности. Для этого достаточно сделать следующий запрос:
SELECT
EMPLOYEE.EMP_NO,
EMPLOYEE.FIRST_NAME,
EMPLOYEE.LAST_NAME,
EMPLOYEE.PHONE_EXT,
EMPLOYEE.HIRE_DATE,
EMPLOYEE.DEPT_NO,
EMPLOYEE.JOB_CODE,
EMPLOYEE.JOB_GRADE,
EMPLOYEE.JOB_COUNTRY,
EMPLOYEE.SALARY,
EMPLOYEE.FULL_NAME,
JOB.JOB_TITLE
FROM
EMPLOYEE, JOB
WHERE
(EMPLOYEE.JOB_CODE = JOB. JOB_CODE) and
(EMPLOYEE.JOB_COUNTRY = JOB. JOB_COUNTRY) and
(EMPLOYEE.JOB_GRADE = JOB. JOB_GRADE)
ORDER BY LAST_NAME

Откроем редактор свойства DataSet_ID для pFIBDataSet1 (или воспользуемся SQL Generator или любым визуальным средством администрирования для InterBase и Firebird) и заменим запрос для SelectSQL с DS_ID, равным 1. Перезапустим приложение без перекомпиляции:

Рис. 9. Приложение с измененным запросом в FIBPlus Repository

Для того чтобы заголовок у поля JOB_TITLE был более удобен для пользователей, вам остается лишь настроить данные о полях таблицы JOB, как мы это делали на самом первом этапе. Мы уверены, что эту операцию вы уже сможете сделаеть самостоятельно.

Резюме
Мы показали, каким образом можно более полно использовать базу данных InterBase и Firebird при разработке приложений. При помощи FIBPlus вы сможете создавать приложения, которые будет легко адаптировать к некоторым меняющимся условиям эксплуатации. Вообще сам процесс разработки может оказаться более простым за счет централизованного хранения настроек и запросов.

Сергей Востриков, Денис Мигачев
Дополнительную информацию можно найти на сайте http://interbase-world.com

Компьютерная газета. Статья была опубликована в номере 22 за 2004 год в рубрике программирование :: разное

Источник

FIBPlus Developer’s Guide 1. FIBPlus Руководство разработчика

1 FIBPlus Developer’s Guide 1 FIBPlus Руководство разработчика

3 FIBPlus Developer’s Guide 3 TFIBLargeIntField. 47 TFIBBCDField. 47 TFIBWideStringField. 47 TFIBBooleanField. 47 TFIBGuidField. 47 Работа с полями-массивами. 48 Использование контейнеров TDataSetsContainer. 49 Дополнительные действия при модификации данных TpFIBUpdateObject. 49 Работа в режиме разделенных транзакций. 50 Пакетная обработка. 51 Перечень свойств TpFIBDataSet. 51 Работа с блоб-полями в клиентских приложениях InterBase и Firebird на основе компонентов FIBPlus. 54 Введение. 54 Использование TpFIBDataSet при работе с BLOB-полями. 54 Использование TpFIBQuery при работе с BLOB-полями. 58 Уникальные возможности FIBPlus: Client BLOB-filters. «Прозрачное» сжатие BLOBполей. 59 Централизованная обработка ошибок TpFIBErrorHandler. 62 Исполнение скриптов TpFIBScripter. 63 Получение событий TFIBSibEventAlerter. 65 Отладка приложений FIBPlus. 65 Мониторинг SQL запросов. 65 Регистрация выполняемых запросов. 65 Репозитории FIBPlus. 66 Репозиторий наборов данных. 66 Репозиторий полей. 67 Репозиторий ошибок. 68 Поддержка FB2.X. 69 Дополнительные возможности. 70 Полная поддержка UNICODE_FSS и UTF Опция компиляции NO_GUI. 70 Использование SynEdit в редакторах. 70 Уникальное расширение FIBPlusTools. 71 Preferences. 71 SQL Navigator. 72 Работа с сервисами. 74 Получение информации о сервере. 74 Управление пользователями сервера. 76 Обслуживание базы данных. 78 Получение статистической информации о состоянии БД. 79 TpFIBDatabase. 80 Свойства. 80 AliasName. 80 BlobSwapSupport. 80 CacheShemaOptions. 80 Connected. 80 ConnectParams. 80 DBName. 81 DBParams. 81 Дополнительные параметры подключения можно посмотреть в документации к

4 FIBPlus Developer’s Guide 4 серверу (APIGuide.pdf, DevGuide.pdf). 81 DefaultTransaction. 81 DefaultUpdateTransaction. 81 DesignDBOptions. 81 LibraryName. 83 SaveAliasParamsAfterConnect. 83 SQLDialect. 83 SQLLogger. 83 SynchronizeTime. 83 TimeOut. 83 UpperOldNames. 83 UseLoginPrompt. 83 UseRepositories. 83 WaitForRestoreConnect. 84 UseBlrToTextFilter. 84 Описание событий. 84 AfterConnect. 84 AfterDisconnect. 84 AfterEndTransaction. 84 AfterLoadBlobFromSwap. 84 AfterRestoreConnect. 84 AfterSaveBlobToSwap. 84 AfterStartTransaction. 84 BeforeConnect. 84 BeforeDisconnect. 85 BeforeEndTransaction. 85 BeforeLoadBlobFromSwap. 85 BeforeSaveBlobToSwap. 85 BeforeStartTransaction. 85 OnAcceptCacheSchema. 85 OnErrorRestoreConnect. 85 OnLostConnect. 85 Public свойства. 86 Методы. 89 TpFIBTransaction. 93 Свойства. 93 DefaultDatabase. 93 Timeout Changed. 93 TimeoutAction. 93 TPBMode. 93 TRParams. 93 UserKindTransaction. 93 TransactionID. 93 State. 93 События. 93 AfterEnd Changed. 94 AfterSQLExecute. 94 AfterStart. 94 BeforeEnd. 94 BeforeSQLExecute. 94 BeforeStart. 94

5 FIBPlus Developer’s Guide 5 OnTimeout. 94 OnIdleConnect. 94 Методы. 94 TpFIBQuery. 96 Свойства. 96 Conditions. 96 Database. 96 GoToFirstRecordOnExecute. 96 Options. 96 ParamsCheck. 97 SQL. 97 Transaction. 97 Свойства. 97 AfterExecute. 97 BeforeExecute. 97 OnBatchError. 97 OnBatching. 97 OnExecuteError. 97 OnSQLChanging. 97 TransactionEnded. 97 TransactionEnding. 97 Методы. 97 Public свойства TpFIBStoredProc TFIBXSQLDA Public свойства Public методы TFIBXSQLVAR Public свойства Public методы TpFIBDataset Свойства Active Filter FilterOptions AllowedUpdateKinds AutoCalcFields AutoCommit AutoUpdateOptions CacheModelOptions Conditions Container Database DataSet_ID Description DefaultFormats DetailConditions FieldOriginalRule Options PrepareOptions RefreshTransactionKind. 111

6 FIBPlus Developer’s Guide 6 SQLs SQLScreenCursor Transaction UniDirectional UpdateRecordTypes UpdateTransaction События AfterEndTransaction AfterEndUpdateTransaction AfterFetchRecord AfterStartTransaction AfterStartUpdateTransaction BeforeEndTransaction BeforeEndUpdateTransaction BeforeFetchRecord BeforeStartTransaction BeforeStartUpdateTransaction DatabaseDisconnected DatabaseDisconnecting DatabaseFree OnApplyDefaultValue OnAskRecordCount OnCompareFieldValues OnFieldChange OnFillClientBlob OnReadBlobField, OnWriteBlobField OnLockError OnLockSQLText TransactionEnded TransactionEnding TransactionFree Методы TpFIBUpdateObject Свойства Conditions DataSet ExecuteOrder KindUpdate OrderInList TDataSetContainer Свойства Active MasterContainer ISGlobal События OnApplyDefaultValue OnApplyFieldRepository OnCompareFieldValues OnDataSetError OnDataSetEvent OnUserEvent. 124

7 FIBPlus Developer’s Guide 7 Методы TSIBfibEventAlerter Свойства AutoRegister Database Events События TpFIBErrorHandler Свойства Options События TpFIBClientDataSet Методы TpFIBDatasetProvider TpFIBScripter Свойства Методы TFIBSQLMonitor Свойства TraceFlags События OnSQL TFIBSQLLogger Свойства Database ActiveStatistics ActiveLogging ApplicationID LogFileName StatisticsParams LogFlags ForceSaveLog Методы TpFIBCustomService Свойства Handle: TISC_SVC_HANDLE ServiceParamBySPB Active ServerName Protocol Params LoginPrompt LibraryName SQLLogger События OnAttach OnLogin Методы TpFIBServerProperties Свойства Option. 130

8 FIBPlus Developer’s Guide 8 DatabaseInfo LicenseInfo LicenseMaskInfo VersionInfo ConfigParams Методы TpFIBSecurityService Свойства SecurityAction UserName Password SQLRole FirstName, MiddleName, LastName UserID GroupID UserInfo UserInfoCount Методы TpFIBBackupService Свойства BackupFile DatabaseName Option. 133

9 FIBPlus Developer’s Guide 9 Соединение с базой данных Для соединения с базой данных (БД) используйте компонент TpFIBDatabase. Подробное описание всех свойств и методов компонента можно прочитать в Приложении. Параметры соединения Параметры соединения являются типичными для сервера InterBase/Firebird: путь к файлу базы данных; имя пользователя и пароль; роль пользователя; набор символов; диалект; клиентская библиотека (gds32.dll для InterBase и fbclient.dll для Firebird). порт используемый сервером при соединении по TCP/IP (только для Firebird) Для задания всех свойств сразу удобно пользоваться встроенным диалогом настройки подключения, представленном на рисунке 1. Диалог «Database Editor» можно вызывать из контекстного меню компонента в designtime. Здесь вы можете указать необходимые параметры, взять параметры из данных псевдонима (Alias) или сохранить их в псевдониме. Замечание: Под псевдонимом подразумевается клиентский псевдоним. псевдонимов под БДЕ. Не надо путать с псевдонимами на стороне сервера. По аналогии с технологией

Читайте также:  Анимешные имена для девушек

11 FIBPlus Developer’s Guide 11 Создание и удаление БД Создать новую базу данных очень просто. Для этого вы должны задать параметры создаваемой БД и вызвать метод CreateDatabase: Delphi with Database1 do begin DBParams.Clear; DBParams.Add(‘USER »SYSDBA» PASSWORD »masterkey»’); DBParams.Add(‘PAGE_SIZE = 2048’); DBParams.Add(‘DEFAULT CHARACTER SET WIN1251’); DBName := ‘SERV_DB:C:\DB\TEST.IB’; SQLDialect := 3; try Database1.CreateDataBase; except // Error handling C++ Database1->DBParams->Clear(); Database1->DBParams->Add(«USER ‘SYSDBA’ PASSWORD ‘masterkey'»); Database1->DBParams->Add(«PAGE_SIZE = 2048»); Database1->DBParams->Add(«DEFAULT CHARACTER SET WIN1251»); Database1->DBName = «SERV_DB:C:\\DB\\TEST.GDB»; Database1->SQLDialect = 3; try < Database1->CreateDatabase(); > catch (. ) < // Error >Замечание: Для создания БД свойство ConnectParams использовать нельзя. Нужно работать с DBParams напрямую. Для удаления БД используйте метод DropDatabase. В момент использования этого метода, вы должны быть подключены к БД. Кэширование метаданных FIBPlus предоставляет нам возможность автоматически получать системную информацию о полях таблиц, самостоятельно настраивая такие свойства полей в TpFIBDataSet как Required (для NOT NULL полей), ReadOnly (для вычислимых полей) и DefaultExpression (для полей, у которых в базе данных задано значение по умолчанию). Это удобно и для программиста, и для пользователя, поскольку первому не нужно заботиться о ручной настройке указанных свойств во время разработки клиентского приложения, а второй получает более осмысленные сообщения при работе с программой. В частности, если какоето поле описано в базе данных как NOT NULL, то при попытке оставить его пустым пользователь получит сообщение «Field must have a value.», что гораздо проще для понимания, чем системная ошибка InterBase/Firebird о нарушении PRIMARY KEY. То же самое касается вычислимых полей, поскольку очевидно, что такие поля нельзя редактировать. FIBPlus автоматически задаст у таких полей свойство ReadOnly равное True, и пользователь не будет мучаться из-за непонятных ошибок при попытке исправить значения этих полей в TDBGrid. Однако данная возможность FIBPlus имеет и свой недостаток, который очевидным образом проявляется при работе с низкоскоростными каналами связи. Чтобы получить

12 FIBPlus Developer’s Guide 12 информацию о полях, компоненты FIBPlus выполняют дополнительные «внутренние» запросы, обращаясь к системным таблицам InterBase/Firebird. Разумеется, при большом количестве таблиц в приложении, а также при большом количестве полей в этих таблицах, работа приложения может замедлиться, а трафик возрасти. Особенно это видно на стадии первоначальных открытий запросов, так как каждый из них сопровождается серией дополнительных. Потом, в процессе работы программы, при повторных запросах, FIBPlus использует уже полученную ранее информацию, однако при старте приложения можно обратить внимание на некоторое замедление работы. TpFIBDatabase позволяет сохранить информацию о метаданных на клиентском компьютере и использовать ее при следующих сеансах работы. Отвечает за это свойство TCacheSchemaOptions. TCacheSchemaOptions = class(tpersistent) property LocalCacheFile: string; property AutoSaveToFile: Boolean.. default False; property AutoLoadFromFile: Boolean.. default False; property ValidateAfterLoad: Boolean.. default True; Свойство LocalCacheFile позволяет задать имя файла, в котором будет сохраняться эта информация. AutoSaveToFile отвечает за автоматическую запись кеша в файл при закрытии приложения. AutoLoadFromFile отвечает за загрузку кеша из файла. И, наконец, ValidateAfterLoad указывает на то, стоит ли проверять сохраненный кеш после загрузки. В дополнение к этим свойствам добавляется событие OnAcceptCacheSchemа, где вы можете указать для каких объектов не нужно загружать сохраненную информацию. Использовать это свойство также очень просто. with pfibdatabase1.cacheschemaoptions do begin LocalCacheFile := ‘fibplus.cache’; AutoSaveToFile := True; AutoLoadFromFile := True; ValidateAfterLoad:= True; Изменение метаданных в процессе работы клиентских приложений может привести к ошибкам в работе клиентов. Чтобы избежать появления этих ошибок можно например сделать триггер на таблицы репозитариев, который выдавал бы определенное событие. По этому событию можно чистить кэш метаданных во время исполнения программы. В модуле pfibdatainfo содержатся классовые переменные на каждый тип кэшируемой информации. Для того чтобы очистить интересующую вас информацию нужно выполнить метод Clear. Также некоторые компоненты имеют методы для точечной очистки кеша, например для определенной таблицы или определенного TpFIBDataSet или даже по коду DataSet_ID из репозитория. ListTableInfo :TpFIBTableInfoCollect; ListDataSetInfo:TpDataSetInfoCollect; ListSPInfo :TpStoredProcCollect; ListErrorMessages:TpErrorMessagesCollect; Кэширование блоб-полей Кэширование блоб-полей на клиентской стороне это еще одна уникальная особенность FIBPlus. При включении BlobSwapSupport.Active := True, FIBPlus будет автоматически сохранять полученные BLOB-поля в указанном каталоге (свойство SwapDir). По умолчанию

13 FIBPlus Developer’s Guide 13 свойство SwapDir принимает значение равное , то есть, равное каталогу, в котором находится исполняемое приложение. При необходимости, можно указать также подкаталог, в котором будут сохраняться BLOB-поля. Например, SwapDir := ‘‘ + ‘\BLOB_FILES\’ В компоненте TpFIBDatabase для поддержки работы с данным свойством существуют 4 события: property BeforeSaveBlobToSwap: TBeforeSaveBlobToSwap; property AfterSaveBlobToSwap: TAfterSaveLoadBlobSwap; property AfterLoadBlobFromSwap: TAfterSaveLoadBlobSwap; property BeforeLoadBlobFromSwap: TBeforeLoadBlobFromSwap; где TBeforeSaveBlobToSwap = procedure(const TableName, FieldName: string; RecordKeyValues: array of variant; Stream: TStream; var FileName: string; var CanSave: boolean) of object; TAfterSaveLoadBlobSwap = procedure(const TableName, FieldName: string; RecordKeyValues: array of variant; const FileName: string) of object; TBeforeLoadBlobFromSwap = procedure(const TableName, FieldName: string; RecordKeyValues: array of variant; var FileName: string; var CanLoad: boolean) of object; Обработчики служат для более гибкого управления процессом сохранения и чтения BLOB-полей с диска. В частности, в обработчиках перед сохранением BLOB-поля можно запретить сохранение конкретного BLOB-поля в зависимости от имени таблицы и поля, значений других полей записи, свободного места на диске и т.д. Регулировать процесс сохранения можно и при помощи свойства MinBlobSizeToSwap, в котором можно задать минимальный размер BLOB-полей, которые будут сохраняться на диске. Технология имеет ряд ограничений: 1. Таблица должна иметь первичный ключ. 2. Чтение BLOB-полей должна производиться компонентом TpFIBDataSet. 3. Приложение само должно следить за свободным местом на диске. В частности, такую функцию можно реализовать в обработчике события BeforeSaveBlobToSwap. 4. К сожалению, после backup/restore базы данных внутри базы данных происходит замена всех BLOB_ID, а потому локальный кэш теряет актуальность и автоматически вычищается. Необходимо пояснить, что при очередном подключении вашего приложения к базе данных, FIBPlus автоматически запускает специальный поток, который в отдельном подключении проверяет весь кэш на диске на наличие соответствующих BLOB-полей в базе данных. Для отсутствующих BLOB-полей файлы сразу же удаляются. Обработка потери соединения FIBPlus предоставляет своим пользователям уникальную возможность обработки потери соединения. Для обработки потери соединения используется сам компонент TpFIBDatabase и компонент централизованной обработки всех ошибок библиотеки TpFIBErrorHandler. Пример использования этой функциональности представлен в примере ConnectionLost. Коротко опишем, как он устроен. Компонент TpFIBDatabase реализует три специальных события: AfterRestoreConnect возникает при успешном восстановлении соединения.

16 FIBPlus Developer’s Guide 16 property Busy:boolean; Возвращает true, если в рамках данного соединения в данный момент выполняется вызов IB API. Имеет смысл анализировать только из параллельного треда. Работа с контекстными переменными Firebird 2. function GetContextVariable(ContextSpace:TFBContextSpace; const VarName:string;aTransaction:TFIBTransaction=nil ):Variant; procedure SetContextVariable(ContextSpace:TFBContextSpace; const VarName,VarValue:string;aTransaction:TFIBTransaction=nil ); Через вышеуказанные методы можно работать с пользовательскими и системными контекстными переменными начиная с версии Firebird2. Подробнее о этих переменных смотрите в документации к серверу, файл «README.context_variables2.txt». Пример использования: procedure TForm1.Button3Click(Sender: TObject); begin ShowMessage(pFIBDatabase1.GetContextVariable(csSystem,’CLIENT_ADDRESS )); pfibdatabase1.setcontextvariable(cssession,’tag’,’tag=1′); ShowMessage(pFIBDatabase1.GetContextVariable(csSession,’TAG’)); Прерывание выполнения запросов в Firebird начиная с версии 2.1. Для прекращения выполнения «долгоиграющих» запросов можно воспользоваться методом TFIBDatabase: procedure CancelOperationFB21(ConnectForCancel:TFIBDatabase=nil); Если сам запрос выполняется в параллельном треде, то метод должен быть вызван из главного. Если же прерываемый запрос выполняется в главном, то метод вызывается из параллельного. Метод использует системную таблицу «MON$STATEMENTS» и выполняется в параллельном соединении, которое ему передается в качестве входного параметра. Если входного параметра нет, то дополнительное соединение будет автоматически создано и закрыто после выполнения метода. Использование этой технологии можно посмотреть в демонстрационном примере BackGroundQuery. Прерывание выполнения запросов в Firebird начиная с версии 2.5. Для решения той же самой задачи, разработчики сервера ввели дополнительную возможность на уровне API сервера, начиная с версии Firebird 2.5. Подробнее смотрите в документации к серверу файл «README.fb_cancel_operation.txt». В FIBPlus эта возможность реализуется набором методов TFIBDatabase

17 FIBPlus Developer’s Guide 17 procedure RaiseCancelOperations; procedure EnableCancelOperations; procedure DisableCancelOperations; Свойство TDesignDBOptions. Служит для управления поведением компонента под дезайном. Возможный набор опций: (ddoisdefaultdatabase,ddostoreconnected,ddonotsavepassword) Значения опций: ddoisdefaultdatabase данный компонент будет под дизайном использоваться как Database по умолчанию. Выражается это в том, что для вновь создаваемых компонент типа: TFIBTransaction, TFIBQuery, TFIBDataset свойства DefaultDatabase и Database будут сразу же заполнены ссылкой на данный компонент. ddostoreconnected Указывает надо ли сохранять свойство Connected установленное под дизайном. Если эта опция выключена, то свойство Connected сохранено не будет и при запуске откомпилированной программы не будет происходить попытки автоматического соединения ddonotsavepassword указывает нужно ли сохранять заполненный под дизайном пароль в ресурсных файлах. Если опция включена, то пароль сохранен не будет.

19 FIBPlus Developer’s Guide 19 Рисунок 2. Диалог Transaction Editor Использование SavePoints Сервера InterBase и их клоны не поддерживают вложенных транзакций. Но InterBase 7.X и Firebird 1.5 поддерживают средства создания контрольных точек сохранения SavePoints и возврата к любой из точек. FIBPlus поддерживает эту функциональность при помощи трех методов: procedure SetSavePoint(const SavePointName:string); procedure RollBackToSavePoint(const SavePointName:string); procedure ReleaseSavePoint(const SavePointName:string); Первый метод устанавливает точку восстановления с именем SavePointName. Второй откатывает транзакцию до состояния в точке SavePointName. Третий освобождает ресурсы сервера, связанные с точкой восстановления SavePointName. Свойство TimeOut property Timeout: Cardinal; property TimeoutAction: TtransactionAction; Если значение свойства Timeout отлично от нуля, то оно определяет время допустимого простоя в миллисекундах. Если за указанный промежуток времени через транзакцию не прошло ни одного действия (запроса, фетча данных, фетча блоба), то она будет автоматически закрыта. Способ закрытия такой транзакции указывается в свойстве TimeoutAction. По умолчанию свойству Timeout присвоено значение 0, т.е. по умолчанию транзакция не закрывается автоматически при простое.

20 FIBPlus Developer’s Guide 20 Двухфазный коммит Одной из особенностей IB/FB серверов является возможность выполнения одной транзакции в нескольких соединениях одновременно. Эта возможность реализуется механизмом двухфазного коммита (2PC). Мы не будем здесь подробно останавливаться на серверной части реализации этой особенности, остановимся на том как эту возможность использовать с помощью FIBPlus. Рекомендуемым способом является использование методов TPFIBTransaction: function AddDatabase(db: TFIBDatabase):integer; function AddDatabase(db: TFIBDatabase; const atrparams: string); Пример использования: procedure TForm1.Button1Click(Sender: TObject); begin pfibtransaction1.adddatabase(pfibdatabase1); pfibtransaction1.adddatabase(pfibdatabase2,’write’#13#10’nowait’#13#10+ ‘concurrency’ ); pfibtransaction1.starttransaction; В первой строке этого кода мы указали транзакции, что она будет выполняться в контексте соединения pfibdatabase1. Поскольку параметров транзакции мы не указали, они будут браться из свойства pfibtransaction1.trparams. Во второй строке мы указали что транзакция будет также выполняться и в контексте соединения pfibdatabase2, но параметры для этого соединения указали явно. При выполнении следующей строки pfibtransaction1.starttransaction; транзакция стартует в обоих указанных соединениях, причем в каждом из них имеет свой собственный набор параметров. Немедленное исполнение запроса (ExecSQLImmediate) Метод TFIBTransaction.ExecSQLImmediate служит для немедленного выполнения запроса, не разбивая это выполнение на стадии препарации, выполнения и освобождения хендла запроса. Служит обверткой вокруг API функции isc_dsql_execute_immediate. Имеет смысл использовать для однократно выполняемых запросов. Например, DDL запросов. Получение информации о состоянии транзакции property Active: Boolean; property InTransaction: Boolean; Свойства показывают активна ли транзакция.

24 FIBPlus Developer’s Guide 24 Производит подготовку запроса к выполнению. Если этот метод не вызван явно, то он будет вызван автоматически во время выполнения запроса. procedure ExecQuery; Запускает выполнение подготовленного(отпрепарированного) запроса. procedure ExecuteImmediate; Запускает выполнение запроса без предварительной препарации. Запросы такого рода, не имеют своего Handle и не требуют его последующего освобождения. Этим методом можно выполнять только запросы не имеющие параметров. procedure ExecProcedure(const ProcName:string); Выполняет сохраненную процедуру по имени ProcName без параметров. Т.е. автоматически формируется тектс запроса вида : Execute Procedure + ProcName и он запускается на выполнение. procedure ExecProcedure(const ProcName:string;const InputParams:array of variant ); Выполняет сохраненную процедуру по имени ProcName с параметрами InputParams. procedure Close; Закрывает селективный запрос. procedure FreeHandle; Освобождает ресурсы сервера ассоциированные с данным запросом. function Next: TFIBXSQLDA; Производит фетч следующей записи для уже выполненного селективного запроса. Если следующей записи нет, то метод возвращает значение nil. Работа с полями запроса property Fields: TFIBXSQLDA; Возвращает результирующие поля запроса. property Fields[const Idx: Integer]: TFIBXSQLVAR; Возвращает ссылку на поле запроса. Параметр Idx указывает на индекс поля в 0 первое поле, 1- второе и т.д. function FieldCount:integer; Возвращает количество полей в запросе. коллекции. function FieldByName(const FieldName: string): TFIBXSQLVAR;

25 FIBPlus Developer’s Guide 25 Возвращает ссылку на поле запроса по имени FieldName. Если поля с таким именем в коллекции полей запроса отстутствует, то генерируется ошибка. function FindField(const FieldName: string): TFIBXSQLVAR; Возвращает ссылку на поле запроса по имени FieldName. Если поля с таким именем в коллекции полей запроса отстутствует, то возвращается значение nil. function FieldByOrigin(const TableName,FieldName:string):TFIBXSQLVAR; Возвращает ссылку на поле запроса по имени таблицы, которой оно принадлежит (TableName) и имени поля в таблице (FieldName). Если такого поля в коллекции полей запроса отстутствует, то возвращается значение nil. Следует так же обратить внимание, что для диалекта 3, все имена таблиц и полей регистрочувствительные. Как следствие, в этот метод надо передавать имена таблицы и поля в том регистре, в котором они созданы в БД. Рассмотрим вышеупомянутые функции на примере нижеследующего кода: var F:TFIBXSQLVAR begin pfibquery1.sql.text:= Select Field1 F1 from Table1 T ; pfibquery1.execquery; F:= pfibquery1.fields[0]; F:= pfibquery1.fieldbyname( F1 ); F:= pfibquery1.findfield ( F1 ); F:= pfibquery1.fieldbyorigin( TABLE1, FIELD1 ); Во всех случаях, в переменную F попадает ссылка на поле F1 запроса. Обратите внимание, что в последнем вызове мы передавали имя поля и таблицы в верхнем регистре. Работа с параметрами запроса property Params: TFIBXSQLDA; Возвращает параметры запроса. function ParamCount:integer; Возвращает количество параметров в запросе. property Params[const Idx: Integer]: TFIBXSQLVAR; Возвращает ссылку на параметр запроса. Параметр Idx указывает на индекс параметра в коллекции. 0 первый параметр, 1- второй и т.д. function ParamByName(const ParamName: string): TFIBXSQLVAR; Возвращает ссылку на параметр запроса по имени ParamName. Если параметра с таким именем в коллекции параметров запроса отстутствует, то генерируется ошибка. function FindParam(const ParamName: string): TFIBXSQLVAR; Возвращает ссылку на параметр запроса по имени ParamName. Если параметра с таким именем в коллекции параметров запроса отстутствует, то возвращается значение nil. Заполнение параметров запроса.

26 FIBPlus Developer’s Guide 26 Перед тем как запрос будет выполнен, необходимо заполнить параметры запроса актуальными значениями. Для этого есть несколько возможностей. Возможность 1: Можно получить ссылку на параметр, и заполнить значение методами TFIBXSQLVAR. var P:TFIBXSQLVAR begin pfibquery1.sql.text:= Select Field1 F1 from Table1 T where F2=:F2 ; P:= pfibquery1.params[0]; P:= pfibquery1.parambyname( F2 ); P:= pfibquery1.findparam( F2 ); P.Value:=1; pfibquery1.execquery; Все три присвоения в переменную P в этом примере, дадут один и тот же результат. Возможность 2: Можно так же воспользоваться методами TpFIBQuery procedure SetParamValues(const ParamValues: array of Variant); procedure SetParamValues(const ParamNames: string;paramvalues: array of Variant); Например : begin pfibquery1.sql.text:= Select Field1 F1 from Table1 T where F2=:F2 and F3=:F3 ; //1 способ pfibquery1.setparamvalues([1,2]); pfibquery1.execquery; //2 способ pfibquery1.setparamvalues([ F1, F2 ],[1,2]); pfibquery1.execquery; Возможность 3: Можно так же воспользоваться методами TpFIBQuery procedure ExecWP(const ParamValues: array of Variant); procedure ExecWP(const ParamNames: string;paramvalues: array of Variant); В отличие от метода SetParamValues метод ExecWP не только заполняет параметры, но и вызывает исполнение запроса. Возможность 4: Можно так же воспользоваться методами TpFIBQuery procedure ExecWPS(ParamSource:ISQLObject; AllRecords:boolean=True); procedure ExecWPS(const ParamSources: array of ISQLObject); При использовании этих методов, в качестве источников для значений полей выступают объекты носители интерфейса ISQLObject. Носителями этого интерфейса являются компоненты pfibdataset, pfibquery, pfibclientdataset. Сам интерфейс описан в юните pfibinterfaces, и в принципе он может может быть имплементирован в любых посторонних компонентах. Рассмотрим применение этих методов на примере. Допустим нам нужно загрузить данные из xml файла и все их вставить в таблицу БД.

27 FIBPlus Developer’s Guide 27 begin pfibclientdataset1.loadfromfile(‘d:\file1.xml’); pfibquery1.sql.text:= Insert into Table1 (ID,Name) Values(:ID,:NAME) ; pfibquery1.execwps(pfibclientdataset1); В первой строчке этого примера, мы загружаем xml файл в pfibclientdataset1. Во второй, формируем запрос на вставку записей в таблицу. Третьей строкой мы отправляем все данные в таблицу. При этом для каждой записи будет происходить следующее: Значение поля ID из pfibclientdataset1 будет присвоено в параметр ID компонента pfibquery1, аналогично поле NAME передаст свое значение параметру NAME. После выполнения запроса на вставку, происходит переход на следующую запись и действия повторяются. В случае возникновения ошибки при операции вставки, вызовется событие OnBatchError, в котором можно эту ошибку обработать и принять решение о продолжении или прекращении дальнейшего выполнения процедуры. Получение дополнительной информации о запросе. property SQLType: TFIBSQLTypes; где TFIBSQLTypes = (SQLUnknown, SQLSelect, SQLInsert, SQLUpdate, SQLDelete, SQLDDL, SQLGetSegment, SQLPutSegment, SQLExecProcedure, SQLStartTransaction, SQLCommit, SQLRollback, SQLSelectForUpdate, SQLSetGenerator,SQLSavePointOperation ); Свойство возвращает тип запроса. Внимание: запрос должен быть уже подготовлен методом Prepare. property SQLKind:TSQLKind; где TSQLKind=(skUnknown,skSelect,skUpdate,skInsert,skDelete,skExecuteProc,skDDL, skexecuteblock); Еще одно свойство возвращающее тип запроса. В отличие от SQLType, оно доступно сразу же при присвоении текста SQL. property Prepared: Boolean; Возвращает true, если запрос уже подготовлен методом Prepare; property Plan: string; Возвращает текст плана, по которому будет выполняться, или уже выполнился запрос. (Запрос должен быть уже подготовлен методом Prepare) property RecordCount: Integer; Возвращает количество отфетченных на данный момент записей. (Только для селективных запросов) property RowsAffected: Integer; Возвращает количество записей на которые воздействовал запрос. (Только для модифицирующих запросов) property AllRowsAffected: TAllRowsAffected; где

Читайте также:  Европейские имена для девочек редкие и красивые

31 FIBPlus Developer’s Guide 31 pfibquery1.conditions.byname(‘by_customer’).active := True; Код для работы с Conditions мог бы выглядеть следующим образом: if pfibquery1.open then pfibquery1.close; pfibquery1.conditions.cancelapply; pfibquery1.conditions.clear; if bycustomerflag then pfibquery1.conditions.addcondition(‘by_customer’, ‘cust_no = 1001’, True); pfibquery1.conditons.apply; pfibquery1.open; В TpFIBDataSet реализованы два дополнительных метода CancelConditions и ApplyConditions, которые вызывают, соответственно, Conditions.Cancel и Conditions.Apply. Код для TpFIBDataSet выглядит немного проще. with pfibdataset1 do begin if Active then Close; CancelConditioins; Conditions.Clear; if bycustomerflag then Conditions.AddCondition(‘by_customer’, ‘cust_no = 1001’, True); ApplyConditions; Open; Использование условий для TpFIBDataSet продемонстрировано в примере ServerFilterConditions Пакетная обработка FIBPlus содержит встроенные методы для пакетной обработки данных, так называемые Batch-методы. Эти методы могут пригодиться для репликации между базами данных, и при операциях импорта и экспорта. function BatchInput(InputObject: TFIBBatchInputStream) :boolean; function BatchOutput(OutputObject: TFIBBatchOutputStream):boolean; procedure BatchInputRawFile(const FileName:string); procedure BatchOutputRawFile(const FileName:string;Version:integer=1); procedure BatchToQuery(ToQuery:TFIBQuery; Mappings:TStrings); Параметр Version введен для совместимости форматов со старыми версиями файлов, выгруженных FIBPlus при помощи метода BatchOutputXXX. Если Version = 1, то используется старый принцип, при котором во внешний файл выводятся только данные в порядке, который определяется полями SQL-запроса. Предполагается, что при чтении данных, сохраненных методом BatchInputRawFile, в читающем SQL параметры будут расположены в том же порядке. Количество полей TpFIBQuery, данные которого записывались, и количество параметров в TpFIBQuery, который потом будет считывать данные, должны совпадать. Для строковых полей необходимо, чтобы длина записываемого поля и читающего параметра также совпадали, однако совпадения имен не требуется. Если Version = 2, то используется новый принцип записи. Помимо данных в файл записывается служебная информация о полях (имя, тип и длина). При последующем чтении, данные будут читаться по принципу совпадения имен. Порядок и количество полей в записывающем TpFIBQuery может не совпадать с порядком и количеством параметров в читающем TpFIBQuery. Типы и длина тоже могут не совпадать. Требуется лишь совпадение имен. Работать с batch-методами очень просто. Покажем это на простом примере. Код,

32 FIBPlus Developer’s Guide 32 приведенный ниже, состоит из трех частей. Первая часть сохраняет данные о клиентах во внешний файл, а вторая загружает эти данные в БД. Третья часть показывает, как можно сделать преобразование данных. < I >pfibquery1.sql := ‘select EMP_NO, FIRST_NAME, LAST_NAME from CUSTOMER’; pfibquery1.batchoutputrawfile(’employee_buffer.fibplus’, 1); < II >pfibquery1.sql := ‘insert into employees(emp_no, FIRST_NAME, LAST_NAME)’+ ‘ values(:emp_no, :FIRST_NAME, :LAST_NAME)’; pfibquery1.batchinputrawfile(’employee_buffer.fibplus’); < III >pfibquery1.sql := ‘select EMP_NO, FIRST_NAME, LAST_NAME from CUSTOMER’; pfibquery2.sql := ‘insert into tmp_employees(emp_no, FIRST_NAME, LAST_NAME)’+ ‘ values(:emp_no, :FIRST_NAME, :LAST_NAME)’; mapstrings.add(’emp_no=emp_no’); mapstrings.add(‘first_name=first_name’); mapstrings.add(‘last_name=last_name’); pfibquery1.batchtoquery(pfibquery2, mapstrings); Мы еще вернемся к пакетной обработке при рассмотрении TpFIBDataSet, который также содержит несколько методов пакетной обработки. При возникновении ошибки выполнения обработки возникает событие OnBatchError. В коде этого события, используя параметр BatchErrorAction (TBatchErrorAction = (befail, beabort, beretry, beignore)) можно принять решение о том, что делать в случае ошибки. Выполнение хранимых процедур Выполнение процедур, практически не отличается от выполнения запросов. Вы просто пишете в тексте SQL ‘execute procedure some_proc(:proc_param)’ либо, для селективных процедур, ‘select * from some_proc(:proc_param)’. Если неселективная процедура возвращает какие-либо результаты, их можно получить после выполнения запроса через уже известное нам свойство Fields. Sql.SQL.Text := ‘execute procedure some_proc(:proc_param)’; Sql.ExecWP([25]); ResultField1 := Sql.Fields[0].AsInteger; Это немного отличается от BDE, ADO и других компонент доступа, где выходные данные доступны также через параметры. Кроме того, в FIBPlus хранимые процедуры можно выполнять при помощи компонента TpFIBStoredProc. Он является прямым наследником TpFIBQuery, у которого есть свойство StoredProcName и его рекомендуется использовать для выполнения неселективных процедур. Выполнение DDL операторов. Кроме выполнения SQL-операторов, компонент TpFIBQuery позволяет выполнять DDL операторы. Для этого необходимо установить свойство ParamsCheck в False. DDL- операции выполняются по одной и никаких разделителей не ставится. В новых версиях для DDL поддержи

34 FIBPlus Developer’s Guide 34 Работа с наборами данных И, наконец, мы подошли к работе с наборами данных. Это компонент TpFIBDataSet. Он работает на основе компонента TpFIBQuery и позволяет кэшировать результаты выборки. TpFIBDataSet является наследником TDataSet и полностью поддерживает все его свойства, события и методы. Для получения более подробной информации о TDataSet смотрите встроенную справку Delphi/C++Builder. Базовые принципы работы с наборами данных TpFIBDataSet позволяет получать, вставлять, изменять и удалять данные. Все операции реализованы при помощи соответствующих компонентов TpFIBQuery в его составе. Для того чтобы выбрать данные, необходимо заполнить свойство SelectSQL. Это равнозначно заполнению свойства SQL компонента QSelect типа TpFIBQuery. Для вставки данных требуется заполнить свойство InsertSQL.Text. Аналогично задаются запросы для модификации (UpdateSQL), удаления (DeleteSQL) и обновления текущей записи (RefreshSQL). Для примера возьмем демонстрационную базу данных employee.gdb (fdb, если это Firebird). Напишем SelectSQL для получения всех служащих, укажем запросы в InsertSQL и т.д. with pfibdataset1 do begin if Active then Close; SelectSQL.Text := ‘select CUST_NO, CUSTOMER, CONTACT_FIRST, CONTACT_LAST from CUSTOMER’; InsertSQL.Text := ‘insert into CUSTOMER(CUST_NO, CUSTOMER, CONTACT_FIRST, CONTACT_LAST )’+ ‘ values (:CUST_NO, :CUSTOMER, :CONTACT_FIRST, :CONTACT_LAST)’; UpdateSQL.Text := ‘update CUSTOMER set CUSTOMER = :CUSTOMER, ‘+ ‘CONTACT_FIRST = :CONTACT_FIRST, CONTACT_LAST = :CONTACT_LAST ‘+ ‘where CUST_NO = :CUST_NO’; DeleteSQL.Text := ‘delete from CUSTOMER where CUST_NO = :CUST_NO’; RefreshSQL.Text := ‘select CUST_NO, CUSTOMER, CONTACT_FIRST, CONTACT_LAST ‘ + ‘from CUSTOMER where CUST_NO = :CUST_NO’; Open; Для того, чтобы открыть TpFIBDataSet, необходимо выполнить метод Open или OpenWP, или установить свойство Active в True. Чтобы закрыть TpFIBDataSet, вызовите метод Close.

35 FIBPlus Developer’s Guide 35

36 FIBPlus Developer’s Guide 36 Рисунок 4. Дилалог SQL Edit TpFIBDataSet Пусть вас не пугает количество написанного текста, все эти запросы сделает за вас редактор TpFIBDataSet, который можно вызвать через контекстное меню компонента. Диалог показан на рисунке 4. Простое приложение, демонстрирующее использование редактируемого TpFIBDataSet, представлено в примере DataSetBasic. Автоматическая генерация обновляющих запросов Кроме использования SQL-редактора TpFIBDataSet, FIBPlus может построить все обновляющие запросы в режиме исполнения программы, и сделать это возможно даже эффективнее, чем при генерации запросов в design-time. Необходимо использовать свойство AutoUpdateOptions. Это очень важная группа настроек, которое можно значительно упростить вам жизнь. TAutoUpdateOptions= class (TPersistent) property AutoParamsToFields: Boolean.. default False; property AutoReWriteSqls: Boolean.. default False; property CanChangeSQLs: Boolean.. default False; property GeneratorName: string; property GeneratorStep: Integer.. default 1; property KeyFields: string; property ParamsToFieldsLinks: TStrings; property SeparateBlobUpdate: Boolean.. default False; property UpdateOnlyModifiedFields: Boolean.. default False; property UpdateTableName: string; property WhenGetGenID: TWhenGetGenID.. default wgnever; property UpdateTableName: string; property WhenGetGenID: TWhenGetGenID.. default wgnever; property UseExecuteBlock :boolean.. default False;

41 FIBPlus Developer’s Guide 41 Операция Описание Subtracts numbers, subtracts dates, or subtracts a number from a date * Multiplies two numbers / Divides two numbers Upper Lower Substring Trim TrimLeft TrimRight Year Month Day Hour Minute Second GetDate Date Time Like In Upper-cases a string Lower-cases a string Returns the substring starting at a specified position Trims spaces or a specified character from front and back of a string Trims spaces or a specified character from front of a string Trims spaces or a specified character from back of a string Returns the year from a date/time value Returns the month from a date/time value Returns the day from a date/time value Returns the hour from a time value Returns the minute from a time value Returns the seconds from a time value Returns the current date Returns the date part of a date/time value Returns the time part of a date/time value Provides pattern matching in string comparisons Tests for set inclusion * Wildcard for partial comparisons. При установленном и неактивном свойстве Filter, можно воспользоваться следующими методами для перемещения по записям, которые удовлетворяют условию фильтрации: FindFirst FindLast FindNext FindPrior На больших объемах данных рекомендуется использовать серверную фильтрацию. Как уже было сказано выше, ее можно осуществить при помощи механизма макросов и условий. Для ознакомления же с локальной фильтрацией рекомендуется изучить пример LocalFiltering. Важно: для того, чтобы получить количество записей, которые попадают под условие фильтрации, используйте функцию VisibleRecordCount вместо RecordCount. Поиск данных После фильтрации логично перейти к поиску данных. TpFIBDataSet поддерживает методы Locate, LocateNext, LocatePrior, описание которых можно получить в стандартной справке Delphi/C++Builder. В дополнение к этим методам добавлены аналогичные методы, которые учитывают

44 FIBPlus Developer’s Guide 44 Необходимо отметить, что при использовании технологии ограниченного локального буфера существует ряд ограничений на другую функциональность TpFIBDataSet: a) нельзя включать режим CachedUpdate; b) свойство RecNo будет возвращать неправильные значения; c) локальная фильтрация не поддерживается; d) работа с BLOB-полями в текущей версии не гарантируется; e) в PrepareOptions необходимо включать опцию psgetorderinfo. Работа с внутренним кэшем набора данных TpFIBDataSet предоставляет вам несколько специальных методов для работы с внутренним буфером, в котором хранятся записи. В общем-то, данные методы превращают TpFIBDataSet в аналог TClientDataSet, ориентированный на InterBase. Единственное отличие состоит в том, что для работы с TpFIBDataSet должно существовать соединение с БД и в SelectSQL должен быть прописан правильный запрос. Несмотря на это ограничение, механизм является достаточно гибким для реализации множества «нестандартных» вещей. Например, следующий запрос создаст выборку из одного целочисленного поля и одного строкового: select cast(0 as integer) some_id, cast(» as varchar(255)) some_name from RDB$DATABASE. Открыть такой TpFIBDataSet можно при помощи метода CacheOpen. После этого становятся работоспособны методы: procedure CacheModify(aFields: array of integer; Values: array of Variant; KindModify: byte ); procedure CacheEdit(aFields: array of integer; Values: array of Variant); procedure CacheAppend(aFields: array of integer; Values: array of Variant); overload; procedure CacheAppend(Value: Variant; DoRefresh: boolean = False); overload; procedure CacheInsert(aFields: array of integer; Values: array of Variant); overload; procedure CacheInsert(Value: Variant; DoRefresh: boolean = False); overload; procedure CacheRefresh(FromDataSet: TDataSet; Kind: TCachRefreshKind ; FieldMap: Tstrings); procedure CacheRefreshByArrMap( FromDataSet: TDataSet; Kind: TCachRefreshKind; const SourceFields, DestFields: array of string ) Так, чтобы добавить запись мы должны выполнить pfibdataset1.cacheinsert([0,1],[255, ‘string1’]) чтобы модифицировать pfibdataset1.cachemodify([0,1],[255, ‘string1’]) чтобы удалить из кеша, просто вызовите CacheDelete; Методы CacheRefresh и CacheRefreshByArrMap позволяют обновить запись на основе данных из другого TpFIBDataSet. Помните, что все эти операции не изменяют БД все действия производятся в буфере TpFIBDataSet. Такую технику иногда можно использовать и в обычном режиме. Например, иногда

46 FIBPlus Developer’s Guide 46 procedure ApplyUpdToBase; Применяет изменения из датасета к базе данных, но отметка о модифицированности с записей не снимается. Поэтому метод CancelUpdates может отменить эти изменения. procedure CommitUpdToCach; Снимает отметки об изменениях со всех записей. Применяется обычно после успешного применения метода ApplyUpdToBase. Принцип работы обоих методов ApplyUpdates и ApplyUpdToBase заключается в том, что совершается проход по буферу датасета и для каждой модифицированной записи применяется InsertSQL,UpdateSQL или DeleteSQL в зависимости от того как именно была модифицирована запись. Кроме того, для каждой записи прежде чем будет вызван соотвествующий SQL запрос, сначала вызывается обработчик OnUpdateRecord. property OnUpdateRecord: TFIBUpdateRecordEvent; где TFIBUpdateRecordEvent=procedure(DataSet: TDataSet; UpdateKind: TUpdateKind; var UpdateAction: TFIBUpdateAction) of object; В этом обработчике вы можете проанализировав запись, изменения по которой сейчас отправляются в базу данных, совершить некие специальные операции и принять решение что с ней делать дальше. Если в ходе работы методов ApplyXXX, произошла ошибка, то для конкретной записи вызовется обработчик property OnUpdateRecord: TFIBUpdateRecordEvent; где TFIBUpdateErrorEvent=procedure(DataSet: TDataSet; E: EFIBError; UpdateKind: TUpdateKind; var UpdateAction: TFIBUpdateAction) of object; В этом обработчике, вы можете проанализировать возникшую ошибку и состояние текущей записи совершить специальные операции по обработке ошибки и принять решение что с записью делать дальше. В обоих вышеописанных обработчиках в качестве результирующего параметра применяется параметр типа TFIBUpdateAction. Вот его описание: TFIBUpdateAction = (uafail, uaabort, uaskip, uaretry, uaapply, uaapplied); uafail прекратить исполнение метода ApplyXXX с сообщением об ошибке uaabort прекратить исполнение метода ApplyXXX без сообщения об ошибке uaskip пропустить применение этой записи uaapply применить изменения этой записи uaapplied пометить эту запись как уже применную и никаких действий не делать uaretry повторить применение этой записи, предполагается что на момент повторения попытки, значения полей скорректированы программным способом. Кроме того следует упомянуть, что в обоих обработчиках вы можете узнать не только текущее состояние записи, но и состояние бывшее до изменений.для этого надо воспользоваться свойством объекта TField OldValue.

47 FIBPlus Developer’s Guide 47 Отдельным вопросом мы рассмотрим работу методов ApplyXXX в сочетании с автогенерируемыми запросами. Если у датасета свойство AutoUpdateOptions. UseExecuteBlock установлено в true, то для всего пакета изменений будет сформирован запрос типа EXECUTE BLOCK. Т.о. сетевой траффик и скорость применения изменений будет существенно оптимизированы. Работает эта опция только для версий сервера начиная с Firebird 2, кроме того, она не может быть применена к датасетам содержащим блоб поля. В заключение темы о кэшированных изменениях приведем пример кода применяющего изменения к базе данных. if pfibdataset1.updatespending then begin pfibdataset1.updatetransaction.starttransaction; try pfibdataset1.applyupdtobase; pfibdataset1.updatetransaction.commit; pfibdataset1.commitupdtocach; except pfibdataset1.updatetransaction.rollback; Использование уникальных типов полей FIBPlus FIBPlus имеет несколько уникальных полей. Это TFIBLargeIntField, TFIBWideStringField, TFIBBooleanField, TFIBGuidField. TFIBLargeIntField представляет собой поле типа BIGINT в Interbase/ Firebird. TFIBBCDField Предназначено для полей типа NUMERIC(x,y) диалекта 3. Т.е. для полей, которые хранятся в 64 битном целом. По умолчанию в TFIBBCDField маппируются только поля, у которых scale меньше 5. Если включить опцию pssqlint64tobcd в PrepareOptions, то и поля с любой scale будут представлены именно BCD полем. Следует заметить, что BCD поле единственное решение, для тех кто хочет не терять точность при отображении и манипулировании данными из 64битных полей. TFIBWideStringField Предназначено для строковых полей в кодировке UNICODE_FSS и UTF8. TFIBBooleanField Эмулирует логическое поле. Стандартного логического поля в Interbase/Firebird нет, но с FIBPlus вы можете его довольно просто эмулировать. Для этого вы должны создать домен (INTEGER или SMALLINT), в имени которого будет содержаться подстрока BOOLEAN. В PrepareOptions TpFIBDataSet должно быть включено свойство psusebooleanfield. Тогда при создании объектов полей FIBPlus будет проверять имя домена, и если там содержится BOOLEAN, то для таких полей будут создаваться экземпляры TFIBBooleanField. CREATE DOMAIN FIB$BOOLEAN AS SMALLINT DEFAULT 1 NOT NULL CHECK (VALUE IN (0,1)); TFIBGuidField Работает аналогично схеме работы TFIBBooleanField т.е. поле должно быть объявлено

50 FIBPlus Developer’s Guide 50 В дополнение к стандартным модифицирующим запросам TpFIBDataSet можно задавать сколь угодно много дополнительных действий. Это осуществляется при помощи объектов TpFIBUpdateObject. Это объект наследник TpFIBQuery, своеобразный клиентский триггер, который позволяет выполнить дополнительные действия для TpFIBDataSet до или после вставки, модификации и удалении. Наследуемые свойства и методы TpFIBQuery читайте в соответствующем разделе Приложения. Например, у вас в программе есть связка мастер-деталь таблицы master(id, name) и detail(id, name, master_id) и при удалении записей из таблицы master вы хотели бы, чтобы автоматически удалялись зависимые данные в таблице detail. Пример немного надуманный, но использование компонента демонстрирует. Итак, чтобы реализовать необходимое поведение добавим pfibupdateobject. Заполним его свойство SQL ‘delete from deatail where master_id = :id’, установим свойство DataSet в датасет для таблицы master, установим KindUpdate в kudelete и, наконец, скажем, что выполнять его нужно перед оператором основного DataSet ExecuteOrder oebeforedefault. Вот и все теперь перед удалением записи из MasterDataSet будет производиться оператор из ассоциированного pfibupdateobject. Работа в режиме разделенных транзакций Как было сказано в разделе «Работа с транзакциями» нужно стремиться делать обновляющие транзакции как можно короче. TpFIBDataSet имеет уникальную возможность работать сразу в контексте двух транзакций: Transaction и UpdateTransaction. Мы рекомендуем этот способ, как наиболее правильный для работы с InterBase/Firebird. Запускается одна длинная транзакция, в которой данные только читаются, и другая короткая транзакция, в контексте которой выполняются все модифицирующие запросы. При этом читающая транзакция (Transaction), как правило, ReadCommited и только для чтения (чтобы не удерживать версии записей). Рекомендуемые параметры для нее: read, nowait, rec_version, read_committed. Пишущая транзакция (UpdateTransaction) короткая и конкурентная, рекомендуемые параметры write, nowait, concurency. В этом случае, при использовании свойства AutoCommit = True, каждое изменение в TpFIBDataSet будет записано в БД немедленно и станет доступным для других пользователей. Вообще для режима разделенных транзакций, крайне рекомендуется включать свойство AutoCommit. Иначе во многом теряется смысл разделения транзакций. Кроме того если не использовать AutoCommit, то возникает вопрос, в какой из транзакций можно корректно производить рефреш записи. Дело в том, что в датасете, после модификации записи возникает ситуация, когда часть записей соотвествует контексту читающей транзакции, а только что модифицированная соответствует контексту пишущей, которая еще не завершена. Конечно, можно делать рефреш записи в контексте пишущей транзакции чтоб видеть изменения, но полное переоткрытие датасета все эти изменения скроет, поскольку они не видны в контексте читающей транзакции. Для управления этой ситуацией существует свойство RefreshTransactionKind:TTransactionKind, которое и определяет в контексте какой транзакции будет осуществлен Refresh. Но нужно понимать, что это полумера и единственной гарантией правильного отображения данных может служить только быстрое завершение пишущей транзакции. Вы должны хорошо представлять себе, в какой момент запускаются и закрываются транзакции в вашем приложении во избежание «непонятных» ситуаций.

Читайте также:  Пароль и имя пользователя для мегафона

51 FIBPlus Developer’s Guide 51 Пакетная обработка У компонента TpFIBDataSet есть несколько методов для выполнения пакетных операций. Это методы BatchRecordToQuery и BatchAllRecordToQuery, которые выполняют SQL-запрос, предварительно настроенный в TpFIBQuery, который передается как параметр. Использование этих методов показано в демонстрационном примере DatasetBatching. Перечень свойств TpFIBDataSet property DefaultFormats: TFormatFields; DateTimeDisplayFormat: формат для DateTime полей NumericDisplayFormat : формат для показа числовых полей NumericEditFormat : формат для редактирования числовых полей DisplayFormatDate : формат для показа Date полей; DisplayFormatTime : формат для показа Time полей; Работает это свойство следующим образом. После открытия датасета, после того как созданы все поля, каждому из полей в свойства DisplayFormat и EditFormat присваивается соответствующий формат из DefaultFormats. В принципе, в обработчике AfterOpen вы можете для отдельных полей переприсвоить формат на любой другой. Для Numeric полей обработка несколько сложнее. Для каждого из них FIBPlus выясняет scale поля, и преобразует формат таким образом, чтоб число знаков после запятой в формате соответствовало scale. Приведем несколько примеров. Допустим у нас есть поле NUMERIC(18,2), посмотрим как оно будет отформатировано при различных значениях NumericDisplayFormat. 1) DefaultFormats.NumericDisplayFormat:= #,###. ; В этом случае в Field.DisplayFormat попадет строка #,###.00. 2) DefaultFormats.NumericDisplayFormat:= #,###.0 ; В этом случае в Field.DisplayFormat тоже попадет строка #,###.00. 3) DefaultFormats.NumericDisplayFormat:= #,###.# ; В этом случае в Field.DisplayFormat попадет строка #,###.##. 4) DefaultFormats.NumericDisplayFormat:= #,### ; В этом случае в Field.DisplayFormat попадет строка #,###. Замечание: Действие свойства можно отключить выключив опцию poautoformatfields в свойстве Options. property DetailConditions:TDetailConditions; Подробно рассмотрено в теме про Master-Detail property FieldOriginRule:TFieldOriginRule; Возможные значения свойства: fornorule,fortableandfieldname,forclientfieldname,fortablealiasandfieldname

52 FIBPlus Developer’s Guide 52 Свойство влияет на результат возвращаемый методом GetFieldOrigin, и соответственно на значение свойств Field.Origin. Рассмотрим на примере. Допустим у нас есть запрос Select T.ID as F from table1 T Посмотрим что будет происходит со свойством Origin поля F в зависимости от значения свойства FieldOriginRule 1) fornorule Origin останется пустым. 2) fortableandfieldname Origin будет иметь значение TABLE1.ID 3) forclientfieldname-origin будет совпадать с клиентским именем поля.т.е. «F». 4) fortablealiasandfieldname Origin будет иметь значение T.ID Замечание: Не для любого поля любого запроса, можно получить Origin. Действительно если посмотреть, например, на запрос Select 1 from RDB$DATABASE, то становится ясно, что для единственного поля этого запроса, никакого Origin существовать не может, потому что нет физического поля в базе данных property RefreshTransactionKind:TTransactionKind; Рассмотрено в теме о режиме разделенных транзакций. property UniDirectional: Boolean; При False все выбираемые записи кэшируются в буфере FIBDataSet, что позволяет после выборки всех записей перемещаться от начала до конца выборки и обратно, не обращаясь к серверу. При True размер буфера ограничен, просмотр записей «вверх» на определенном этапе будет невозможен. Значение True имеет смысл выставлять, если датасет участвует в каком-нибудь однопроходном процессе, например формировании отчета на основе данных выборки. property Options:TpFIBDsOptions; Набор опций регулирующий разные аспекты поведения датасета. отдельности. Рассмотрим их по potrimcharfields если включено то в полях типа char будут обрезаться хвостовые пробелы. porefreshafterpost Определяет нужно ли делать автоматический Refresh Post porefreshafterdelete Определяет нужно ли делать автоматический Refresh Delete после после porefreshdeletedrecord- Определяет что делать с записью, если Refresh записи обнаружил ее отсутствие в базе данных. Т.е. запись вероятней всего была удалена, либо перестала попадать в условие выборки. Если этот флаг включен, то в этом случае запись будет вычеркнута из буфера датасета. postarttransaction Определяет нужно ли автоматически стартовать транзакцию при попытке открытия датасета.

53 FIBPlus Developer’s Guide 53 poautoformatfields Включает действие свойства DefaultFormats. poprotectededit Включает режим пессимистической блокировки. pouseselectforlock Описано в теме о пессимистической блокировке. pokeepsorting Описано в теме о локальной сортировке. popersistentsorting Описано в теме о локальной сортировке. povisiblerecno Определяет значение возврата метода Recno в случае если он применяется к отфильтрованному датасету. Если установлен флаг povisiblerecno, то метод Recno будет возвращать не номер записи в полном буфере, а номер записи в уже отфильтрованной его части. ponoforceisnull Действие аналогично опции qonoforceisnull в TpFIBQuery. pofetchall Определяет фетчить ли все записи сразу же после открытия датасета. pofreehandlesafterclose Действие аналогично опции qofreehandleafterexecute в TpFIBQuery. pocachecalcfields Оптимизирует внутреннюю работу c Calc полями. property PrepareOptions: TpPrepareOptions; Набор опций регулирующий разные аспекты поведения датасета. отдельности. Рассмотрим их по pfsetrequiredfields если включено то в Fields датасета будет автоматически заполняться свойство Required. Для NOT NULL полей оно будет принимать значение True, для остальных False. (Эта опция не вызывает дополнительные запросы к базе) pfsetreadonlyfields Если включено, то те поля датасета, которые не участвуют в модифицирующих запросах, автоматически становятся ReadOnly. Т.е. их нельзя будет изменять даже в буфере датасета. Кроме того становятся ReadOnly те поля, которые являются калькулируемыми на сервере. (Эта опция вызывает дополнительные запросы к базе, с целью выяснить какие поля являются server-calculated) pfimportdefaultvalues Если включено, то те поля датасета, которые в базе имеют значение по умолчанию, автоматически получат соответствующее значение в свойство DefaultExpression. Это свойство используется при Insert/Append новой записи. (Эта опция вызывает дополнительные запросы к базе, с целью получения текста значения по умолчанию) pfimportdefaultvalues Если включено, то те поля датасета, которые в базе имеют значение по умолчанию, автоматически получат соответствующее значение в свойство DefaultExpression. Это свойство используется при Insert/Append новой записи. (Эта опция вызывает дополнительные запросы к базе, с целью получения текста значения по умолчанию) psusebooleanfield Если включено, то датасет сможет использовать Boolean поля. Подробнее см. в теме «Использование уникальных типов полей». (Эта опция вызывает дополнительные запросы к базе, с целью получения домена поля) psuseguidfield Если включено, то датасет сможет использовать GUID поля. Подробнее см. в теме «Использование уникальных типов полей» (Эта опция вызывает дополнительные запросы к базе, с целью получения домена поля pssqlint64tobcd Если включено, то датасет будет использовать TBCDField для полей типа NUMERIC(x,y), где y больше 4. Подробнее см. в теме «Использование уникальных типов полей» (Эта опция не вызывает дополнительные запросы к базе)

55 FIBPlus Developer’s Guide 55 Рис. 1. Внешний вид формы приложения для работы с BLOB-полями. Для вывода изображений, сохраненных в поле GRAPHIC, мы будем использовать стандартный компонент DBIMage1: TDBImage. Очевидно также, что запросы при работе с BLOB-полями внешне ничем не отличаются от запросов со стандартными типами полей: SelectSQL: SELECT * FROM BIOLIFE UpdateSQL: UPDATE BIOLIFE Set CATEGORY=?NEW_CATEGORY, COMMON_NAME=?NEW_COMMON_NAME, SPECIES_NAME=?NEW_SPECIES_NAME, LENGTH CM_=?NEW_LENGTH CM_, LENGTH_IN=?NEW_LENGTH_IN, NOTES=?NEW_NOTES, GRAPHIC=?NEW_GRAPHIC WHERE InsertSQL: INSERT INTO BIOLIFE( ID, CATEGORY, COMMON_NAME, SPECIES_NAME, LENGTH CM_, LENGTH_IN, NOTES, GRAPHIC ) VALUES (?NEW_ID,?NEW_CATEGORY,?NEW_COMMON_NAME,?NEW_SPECIES_NAME,?NEW_LENGTH CM_,?NEW_LENGTH_IN,

62 FIBPlus Developer’s Guide 62 Запустите приложение, удалите записи, которые уже содержались в нем и добавьте новые. Вы не увидите никакой разницы, но если заглянуть на то, что реально было сохранено в BLOB поле, станет ясно, что данные были заархивированы: Рис. 3. Данные в BLOB-поле, упакованные при помощи локального фильтра FIBPlus. Итак, приложение отсылает на сервер (и получает с сервера) уже заархивированные BLOB поля, и, таким образом, сетевой трафик значительно снижается! Конечно, вы можете упаковывать BLOB поля, не используя вышеописанный механизм BLOB фильтров. Например, вы можете сжимать поле в процедуре Button1Click перед его сохранением, а затем распаковывать его в обработчике AfterScroll (или делать что-то подобное). Но, во-первых, предлагаемый централизованный механизм значительно упрощает ваш код (так как BLOB поля обрабатываются независимо от других частей программы), а, во-вторых, он помогает избежать типичных ошибок (например, когда вы пакуете BLOB поля в одной части программы и не делаете то же самое в другой). Централизованная обработка ошибок TpFIBErrorHandler FIBPlus позволяет централизованно обрабатывать ошибки и исключительные, которые возникают при работе «своих» компонентов. Для этого существует компонент TpFIBErrorHandler с единственным событием OnFIBErrorEvent: TOnFIBErrorEvent = procedure(sender: TObject; ErrorValue: EFIBError; KindIBError: TKindIBError; var DoRaise: boolean) of object; где TKindIBError = (kenoerror, keexception, keforeignkey, kelostconnect, kesecurity, kecheck, keuniqueviolation, keother); EFIBError = class(edatabaseerror) //.. property SQLCode : Long read FSQLCode ; property IBErrorCode: Long read FIBErrorCode ; property SQLMessage : string read FSQLMessage; property IBMessage : string read FIBMessage; Опция DoRaise управляет дальнейшим поведением библиотеки после выполнения

63 FIBPlus Developer’s Guide 63 обработчика, то есть, указывает, будет ли генерироваться стандартное исключение или нет. Опция может быть использована для стандартной обработки различных типов ошибок перечисленных в KindIBError. Начиная с версии FIBPlus 6.4.2, в компонент были добавлены новые свойства, которые позволяют корректно работать с локализированными сообщениями сервера. Вы должны в свойстве ErrorLexems указать такие строковые подсвойства как Index, Constraint, Exception и At. Исполнение скриптов TpFIBScripter Данный компонент предназначен для анализа и исполнения скриптов. Если скрипт планируется исполнять в рамках конкретного соединения, то в компоненте необходимо установить свойство Database. Если в рамках конкретной транзакции, то необходимо установить и свойство Transaction. Важно то, что если свойство Database не установлено, то в скрипте обязан существовать стейтмент CREATE DATABASE или CONNECT DATABASE. Еще один важный момент, все соединения по умолчанию делаются с диалектом равным 3. Для того чтоб указать другой диалект, необходимо в начале скрипта прописать стейтмент SET SQL DIALECT x где x номер диалекта. Для выполнения скрипта компонент имеет два метода: procedure ExecuteScript (FromStmt:integer=1); procedure ExecuteFromFile(const FileName: string;terminator:char=’;’) ; Первый метод выполняет скрипт, текст которого уже находится в памяти, и расположен в свойстве Script:TStrings. Скрипт выполняется начиная со стейтмента указанного во входном параметре FromStmt. Второй метод выполняет скрипт, текст которого находится в файле. Важно знать, что ExecuteFromFile не загружает весь файл в память, а считывает файл построчно. Это с одной стороны позволяет обрабатывать очень большие скрипты (например скрипт содержащий не метаданные, а команды на заполнение базы). С другой стороны этот подход может несколько замедлять процесс исполнения, поэтому если у вас скрипты не сильно большие, то имеет смысл вместо ExecuteFromFile использовать следующий код pfibscripter1.script.loadfromfile(filename); pfibscripter1.executescript; Во время выполнения скрипта, вы можете отслеживать прогресс исполнения в обработчиках property BeforeStatementExecute:TOnStatementExecute; property AfterStatementExecute:TOnStatementExecute; где TOnStatementExecute = procedure(sender: TObject;Line:Integer; StatementNo: Integer; Desc:TStatementDesc; Statement: TStrings) of object; Пример использования procedure TForm1.pFIBScripter1BeforeStatementExecute(Sender: TObject; Line, StatementNo: Integer; Desc: TStatementDesc; Statement: TStrings); begin StatusBar1.Panels[0].Text:=’Execute Statement No ‘+IntToStr(StatementNo); ProgressBar1.Max:=pFIBScripter1.StatementsCount;

64 FIBPlus Developer’s Guide 64 ProgressBar1.Position:=StatementNo; Application.ProcessMessages Приостановить выполнение скрипта можно используя свойство property Paused: Boolean read FPaused write FPaused; Ошибки исполнения конкретных стейтментов можно обрабатывать в обработчике property OnExecuteError:TOnSQLScriptExecError; TOnSQLScriptExecError = procedure(sender: TObject; StatementNo: Integer; Line:Integer; Statement: TStrings; SQLCode: Integer; const Msg: string; var dorollback:boolean; var Stop: Boolean) of object; В нем вы можете проанализировать ошибку, сообщение об ошибке, узнать строку скрипта с которой начинается ошибочный стейтмент, проанализировать сам стейтмент и принять решение о завершении транзакции и завершении выполнения скрипта. Кроме выполнения скрипта целиком, существует несколько методов для его анализа и выборочного выполнения некоторых стейтментов. procedure Parse(Terminator:Char=’;’); Выполняет анализ скрипта. С него явно или неявно начинается вся работа с текстом скрипта. Если вы запускаете скрипт на выполнение, то явного вызова метода Parse не требуется. Если же вы хотите анализировать скрипт или выборочно выполнить из него несколько стейтментов, то метод Parse придется вызвать явно. function StatementsCount:integer; Возвращает количество стейтментов в скрипте. function GetStatement(StmtNo:integer;Text:TStrings):PStatementDesc; По номеру стейтмента возвращает указатель на структуру TStatementDesc = record smdbegin:tstmtcoord; smdend :TStmtCoord; smttype :TStmtType; objtype :TObjectType; objname :string; По ней вы можете узнать координаты стейтмента в тексте, тип стейтмента и тип объекта который создается этим стейтментом. Кроме того, во входном параметре Text вы можете получить текст стейтмента с указанным номером. procedure ExecuteStatement(StmtTxt:TStrings;stmt:PStatementDesc;StmtNo:integer; TmpSQL:TStrings=nil;LineInFile:integer=-1 ); Метод позволяет выполнить стейтмент который был предварительно получен методом GetStatement. Приведем пример исполнения скрипта начиная с 3 стейтмента. procedure TForm1.ToolButton1Click(Sender: TObject);

68 FIBPlus Developer’s Guide 68 TonApplyFieldRepository=procedure(DataSet:TDataSet;Field:TField;FieldInfo:TpFIBFieldInfo) of object; который позволяет разработчику легко использовать свои собственные настройки в репозитарии полей. Например, если хочется настраивать свойство EditMask, то добавляем в таблицу репозитория поле EDIT_MASK, в приложении ставим контейнер, делаем его глобальным. В обработчике OnApplyFieldRepository пишем: procedure TForm1.DataSetsContainer1ApplyFieldRepository(DataSet: TDataSet; Field: TField; FieldInfo: TpFIBFieldInfo); begin Field.EditMask:=FieldInfo.OtherInfo.Values[‘EDIT_MASK’]; Рисунок 6. Репозиторий полей Репозиторий ошибок Доступ к репозиторию открывается через контекстное меню компонента TpFIBDatabase «Edit error messages table». Здесь вы можете задать свои собственные сообщения об ошибках для таких ситуаций как нарушение уникальности PK, ограничений unique, ограничений FK, ограничений checks и уникальных индексов. Для использования репозитория необходимо поместить на какую-либо форму или модуль проекта компонент TpFIBErrorHandler, и включить использование этого репозитория. Все тексты возникающих ошибок, которые содержатся в репозитории, будут автоматически заменены вашими сообщениями.

69 FIBPlus Developer’s Guide 69 Рисунок 7. Репозиторий ошибок Поддержка FB2.X Несмотря на то, что на момент написания этого документа доступна только первая публичная бета-версия Firebird 2.0, FIBPlus полностью совместим с этой версией сервера. Теперь в SelectSQL можно пользоваться конструкциями Execute block Опция poaskrecordcount теперь во всех случаях работает правильно т.к. используется конструкция select count from (select ваша оригинальная выборка). В компонент TpFIBDatabase добавлены два метода для поддержки новых команд RDB$GET_CONTEXT и RDB$SET_CONTEXT введенных в Firebird 2: function GetContextVariable (ContextSpace: TFBContextSpace; const VarName: string): Variant; procedure SetContextVariable (ContextSpace: TFBContextSpace; const VarName, VarValue: string); FIBPlus поддерживает конструкцию FB2.0 insert. into. returning. Теперь можно не заботиться о получении с клиента значения генератора, а оставлять его на триггере. Появилась возможность использования RDB$DB_KEY. Новые возможные техники работы с insert returning и RDB$DB_KEY показаны в примере FB2InsertReturnin. Если у вас есть запросы соединения таблицы с самой собой: Select * from Table1 t, Table1 t1 where. то только в версии Firebird 2.0 для каждого поля FIBPlus может четко «понять», откуда оно взялось: из t или t1. Эта особенность используется внутри компонентов FIBPlus для правильной генерации модифицирующих запросов.

72 FIBPlus Developer’s Guide 72 AutoUpdateOptions у TpFIBDataSet. Имя генератора в AutoUpdateOptions генерируется из названия таблицы (UpdateTable), префикса и суффикса. Следующие страницы диалога позволяют настраивать ключевые свойства компонентов TpFIBDataBase, TpFIBTransaction и TpFIBQuery. В частности, если вы всегда работаете с новыми версиями InterBase, то есть, с версиями 6 и более (а также Firebird), то мы рекомендуем вам задать значение SQL Dialect на закладке TpFIBDatabase равным 3, чтобы каждый раз не переключать это свойство «вручную». SQL Navigator Это наиболее интересная часть FIBPlus Tools, не имеющая аналогов в других продуктах. Фактически, это инструмент централизованной обработки SQL в рамках целого приложения. SQL Navigator позволяет разработчику получить доступ к свойствам SQL любого компонента приложения и все это в одном месте. Кнопка «Scan all forms of active project» сканирует все формы приложения и выделяет из них те, которые содержат компоненты FIBPlus для работы с SQL: TpFIBDataSet, TpFIBQuery, TpFIBUpdateObject и TpFIBStoredProc. Нажмите в списке на любую из обнаруженных форм. Список справа будет заполнен компонентами, обнаруженными на этой форме. Нажатие на любой из компонентов позволит нам посмотреть соответствующие свойства, в которых содержится SQL-код. Для компонентов класса TpFIBDataSet будут выведены свойства: SelectSQL, InsertSQL, UpdateSQL, DeleteSQL и RefreshSQL. Для компонент TpFIBQuery, TpFIBUpdateObject и TpFIBStoredProc будет выведено значение свойства SQL. Вы можете изменить любое свойство напрямую из SQLNavigator, и новое значение будет сохранено. SQLNavigator позволяет делать операции с группами компонент. Для этого достаточно пометить соответствующие компоненты или даже формы. Save selected SQLs сохраняет значения выделенных свойств во внешний файл. Check selected SQLs проверяет корректность выделенных запросов прямо в SQLNavigator. Записанный файл с выделенными запросами можно использовать для дальнейшего анализа при помощи специализированных инструментов. Вы можете использовать SQLNavigator для поиска текста в SQL в рамках всего проекта.

73 FIBPlus Developer’s Guide 73 Рисунок 9. Tools SQL Navigator При помощи двойного нажатия на каждом найденном элементе SQLNavigator выберет компонент и свойство, чтобы разработчик мог редактировать SQL.

Источник

Оцените статью
Имя, Названия, Аббревиатуры, Сокращения
Adblock
detector