Компоненты IBExpress   (Скачать) (Версия для Lazarus 1.7 trunk Скачать)

Тестовое приложение с IBX для Lazarus (Скачать)

Это модифицированная версия IBX, основные изменения - это поддержка 2х транзакций пишущей и читающей, добавлены дополнительные свойства, а т.ж. изменен доступ к API, TIBDatabase загружает клиентскую библиотеку в момент соединения с базой и освобождает при отсоединении, благодаря этому можно работать из одного приложения с серверами разных версий.

Пример использования возвращаемых значений

Пример использования EXECUTE BLOCK

Использование раздельных транзакций

Сортировка TIBCustomDataSet

Дополнительные свойства TIBCustomDataSet

Пример использования возвращаемых значений из Insert, Update запрсов, из EXECUTE BLOCK и EXECUTE PROCEDURE

Возвращаемые значения в IBX главным образом используются для механизма получения первичного ключа, который генерится на стороне сервера при вставке записи. В этом случае не нужно заботиться о гененрации ключа на стороне клиента. Если имена возвращаемых параметров из TIBDataSet.QInsert,TIBDataSet.QModify совпадают с именами полей, то значения параметров подставятся в набор данных автоматически после выполнения метода TIBDataSet.Post. Пример:

*************************************************************************************************************

IBDataSet1.InsertSQL.Text:

INSERT INTO PIPLE (FAM, IMJA, OTCH) VALUES (:FAM, :IMJA, :OTCH) RETURNING PIPLE_ID

*************************************************************************************************************

Таблица PIPLE триггер BEFORE INSERT

CREATE OR ALTER TRIGGER PIPLE_BI FOR PIPLE

ACTIVE BEFORE INSERT POSITION 0

AS

BEGIN

IF (NEW.PIPLE_ID IS NULL) THEN

NEW.PIPLE_ID = GEN_ID(GEN_PIPLE_ID,1);

END

*************************************************************************************************************

IBDataSet1.Insert;

IBDataSet1.FN('FAM').AsString := 'Иванов';

IBDataSet1.FN('IMJA').AsString := 'Иван';

IBDataSet1.FN('OTCH').AsString := 'Иванович';

IBDataSet1.Post;

*************************************************************************************************************

После выполнения метода Post сработает SQL запрос IBDataSet1.InsertSQL он в свою очередь производит вставку записи и возвращает значение первичного ключа, которое генерится в триггере BEFORE INSERT. После получения параметра 'PIPLE_ID' из IBDataSet1.QInsert, значение будет подставлено в набор данных IBDataSet1, после этого автоматически срабатывает Refresh по первичному ключу.

Возвращаемые значение можно получать из EXECUTE BLOCK и EXECUTE PROCEDURE, в этом случае процедура или блок будут выглядеть примерно так:

EXECUTE BLOCK (FAM VARCHAR(30) = :FAM, IMJA VARCHAR(30) = :IMJA, OTCH VARCHAR(30) = :OTCH)

RETURNS (PIPLE_ID BIGINT)

AS

BEGIN

IF ((FAM IS NULL) OR (FAM = '')) THEN EXCEPTION ER_ERROR 'Не указана фамилия';

INSERT INTO PIPLE (FAM, IMJA, OTCH) VALUES (:FAM, :IMJA, :OTCH) RETURNING PIPLE_ID INTO :PIPLE_ID;

SUSPEND;

END

Если объявлены возвращаемые значения в EXECUTE BLOCK, то команда SUSPEND обязательна. Компоненты могут принять только одну троку с возвращаемыми параметрами, если запрос из EXECUTE BLOCK возвращает более одной строки, возникнет исключение.

В случае с хранимой процедурой, оператор SUSPEND не нужен.

Если используется TIBQury или TIBStoredProc, то для работу с возвращаемыми параметрвми предусмотрены свойства:

TIBQurey.OutParams: TParams

TIBQurey.OutParamsCount: Integer

TIBQury.OutParamByName(ParamName: string): TParam

TIBStoredProc.OutParamsCount: Integer

TIBStoredProc.OutParamByName(ParamName: string): TParam

TIBStoredProc.Params: TParams

У TIBStoredProc.Params указывает на список возвращаемые параметры, у TIBQuery для работы с возвращаемыми параметрами предусмотрен TIBQurey.OutParams.

Использование EXECUTE BLOCK

Инструкция EXECUTE BLOCK поддерживается в TIBDataSet.InsertSQL, TIBDataSet.ModifySQL, TIBDataSet.DeleteSQL, в TIBQuery, в TIBStoredProc.

IBQury1.SQL:

********************************************************************

EXECUTE BLOCK (INPARAM1 INTEGER = :INP1)

RETURNS (RETPARAM VARCHAR(50))

AS

BEGIN

RETPARAM = 'Выход ' || INPARAM1;

SUSPEND;

END

********************************************************************

Если объявлены возвращаемые значения в EXECUTE BLOCK, то команда SUSPEND обязательна. Компоненты могут принять только одну троку с возвращаемыми параметрами, если запрос из EXECUTE BLOCK возвращает более одной строки, возникнет исключение.

Пример выполнения вышеприведенного SQL запроса с EXECUTE BLOCK через TIBQury:

*****************************************************************************

IBQuery1.PN('INP1').AsInteger := 100;

IBQuery1.ExecSQL;

if IBQuery1.OutParamCount > 0 then

ShowMessage(IBQuery1.OutParamByName('RETPARAM').AsString);

******************************************************************************

Инструкция EXECUTE BLOCK поддерживается в компоненте TIBStoredProc, через свойство SQL, так-же как и в TIBQuery.

Использование раздельных транзакций

Компонента TIBDataSet использует для своей работы 2 транзакции: Transaction и UpdateTransaction. Смысл использоания раздельных транзакций - максимально исключить возможность получения во время работы мертвых блокировок (DEAD LOCK). Исследования по использованию оптимальных параметров раздельных транзакций проводила компания Devrice на FIBPlus, я могу лишь подтвердить, что используя их рекомендации, у меня проблем не было.

Запросы из TIBDataSet.QSelect (и QRefresh в большинстве случаев) работают через читающую транзакцию (Transaction). Для читающей транзакции могу рекомендовать параметры (в редакторе компонента TIBTransaction соответствует пункту ReadCommited)

read, read_committed, rec_version, nowait

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

Модифицирующие запросы из QInsert, QModify, QDelete выполняются через UpdateTransaction. Для пишущей транзакции могу рекомендовать параметры (в редакторе компонента TIBTransaction соответствует пункту FBWRite):

write, wait, no_rec_version, read_committed, lock_timeout=10

В TIBDataSet, после метода Post автоматически стартует Refresh, выполняя SQL запрос из TIBDataSet.RefreshSQL. При выполнении этого запроса, QRefresh сам выбирает себе транзакцию. В случае, если на момент старта Refresh запроса UpdateTransaction активна, такое может быть при AutoCommit = False, т.е. ручное управление транзакциями, то предполагается, раз транзакция модифицирующего запроса не подтверждена, то изменения сделанные запросом будут видны лишь через модифицирующую транзакцию, поэтому Refresh пройдет через UpdateTransaction, во всех других случаях будет использована Transaction.

Обычно в приложении для TIBDataSet с AutoCommit = True достаточно использовать 1 читающую и 1 пишущую транзакцию. Читающую транзакцию можно открыть при старте приложения вручную (в этом случае AutoCommit для неё работать не будет) и закрывать её то-же руками, когда приложение завершает работу, в этом случае, когда наборы данных приходится много раз закрывать и открывать не будут сбрасываться значениея уже установленных параметров в TIBDataSet. Но если вы используете блобы, лучше сделать для них отдельную читающую транзакцию, время жизни которой лучше ограничить временм обращения к серверу для выполнения читающего запроса, по причине описанной выше.

Сортировка TIBCustomDataSet

Для сортировки данных в TIBCustomDataSet введено public свойство OrderFields. Это свойство не осуществляет сортировку локального кэша, а изменяет или добавляет SQL инструкцию ORDER BY к SELECT запросу. Можно использовать ASC и DESC после имен полей, несколько значаний перечисляются через запятую.

IBDataSet.PN('GOD').AsInteger := 2015;

IBDataSet.Open;

IBDataSet1.OrderFields := 'GROUPNAIM, SUBGROUPNAIM DESC';

Дополнительные свойства TIBCustomDataSet

TIBCustomDataSet.AutoCancel: Boolean - работает совместно с AutoCommit и если AutoCommit := True и AutoCancel := True и когда в наборе данных выполняется отмена вставки или редактирования строки TIBDataSet.Cancel, то происходит проверка UpdateTransaction и если транзакция активна, такое могло произойти если во время операции TIBDataSet.Post произошла ошибка, то транзакция автоматически завершается.

TIBCustomDataSet.DefFormats - свойство в виде структуры которая задает форматы для отображения дат и чисел.

TIBCustomDataSet.DefValueFormServer: Boolean - если True то перед вставкой новой записи извлекает значения по умолчанию для полей заданные при создании таблицы и подставляет их в новую запись.

TIBCustomDataSet.DetailConditions - параметры задают поведение для связки Master - Detail. Если назначен набор данных Master через свойство DataSource то:

TIBCustomDataSet.DetailConditions.dcForceMasterPost - если True, то перед методом Post проверяет набор данных Master и если он в режиме dsInsert или dsEdit, то выполняет ему Post.
TIBCustomDataSet.DetailConditions.dcForceMasterRefresh - если True, то после метода Post вызывает у набора данных Master.Refresh. Метод обработки события Refresh у мастера переделан и если после Master.Refresh строка не изменилась (парметры по которым происходит связка с Detail), то набор данных Detail не переоткрывается.
TIBCustomDataSet.DetailConditions.dcForceOpenClose - если True, то набор данных автоматически открывается и закрывается при открытии и закрытии набора данных Master

TIBCustomDataSet.DetailConditions.FieldsFormats - позволяет задать персональные форматы отображения для отдельных полей

TIBCustomDataSet.DetailConditions.EditFormats - позволяет задать персональные форматы редактирования для отдельных полей