...
...

Без BDE?

FreeIBComponents(в дальнейшем FIBC) — набор компонент Delphi и C++ Builder, обеспечивающиx непосредственный доступ к СУБД IBDatabase (Interbase,IB). Автор Gregory Deatz ( ). Найти FIBC можно на http://www.interbase.com/downloads/ .Для работы приложения, использующего FIBC для доступа к IB, BDE не требуется. И это несколько радует:).
Почему я выбрал FIBC, а не IBObjects, например?
1. FIBC — freeware, с исходниками.
2. Я много работал с BDE, и поэтому большинство свойств и методов компонент, входящих в FIBC, мне были известны.
3. При работе с FIBC можно использовать стандартные Data-aware компоненты из поставки Delphi.
4. FIBC содержит всего пять компонент.
Конечно, есть и недостатки — это прежде всего отсутствие технической поддержки и наличие багов (ну куда без них?). Зато можно спокойно поковырять исходники;).
В поставку FIBC (версия от 04.01.99) входят:
TFIBDatabase — компонент, обеспечивающий соединение с IB. Некий аналог TDatabase, но TFIBDatabase напрямую не управляет транзакциями.
Некоторые свойства:
Connected:Boolean — показывает, установлено ли соединение с БД. Следует установить в True, чтобы установить соединение с БД.
DBName:String — содержит путь к БД. Если подключение к удаленному серверу осуществляется посредством TCP/IP, то содержит <server name>:<file name on server>, где <server name> — имя удаленного сервера (или IP-адрес), а < file name on server > — ioou e oaeeo AA ni noi?iiu na?aa?a. A neo?aa eniieuciaaiey i?ioieiea NetBeui используется следующий синтаксис: \\<server name\<file name on server>.

DBParams : Tstrings — параметры соединения c БД, например имя пользователя, роли, пароль, языковой драйвер и т.д. TFIBDatabase содержит метод CreateDatabase, который позволяет создать БД. Перед выполнением метода DBParams должно содержать параметры создания БД. Более подробно о параметрах можно узнать из документации по API, а также из реализации процедуры GenarateDPB (FIB.pas).

DefaultTransaction: TFIBTransaction — транзакция по умолчанию. Как уже говорилось, TFIBDatabase не управляет транзакциями, но это свойство позволяет определить транзакцию, которую использует TFIBDatabase в первую очередь. Например, если транзакция явно не указана и свойство Database компонента TFIBQuery указывает на компонент TFIBDatabase, свойство DefaultTransaction которого указывает на TFIBTransaction, то это предполагает, что все SQL-запросы, генерируемые TFIBQuery, будут выполняться в контексте транзакции, определенной компонентом TFIBTransaction. Но во избежание всяких неожиданностей, я предпочитаю явно указывать транзакцию.

TimeOut:Integer —
время ожидания в миллисекундах, по истечении которого произойдет завершение соединения с БД.

TFIBTransaction
— компонент для управления транзакциями.
Некоторые Published-свойства:
Active:Boolean — показывает, активна ли транзакция. Чтобы сделать транзакцию активной, нужно установить в True. Установка в False приводит к тому, что транзакция становится неактивной и происходит ioeao (Roll back) до состояния, когда было произведено последнее подтверждение изменений (Commit).

TimeOut:Integer — время ожидания в миллисекундах, по истечении которого произойдет автоматическое подтверждение или откат изменений (в зависимости от значения свойства TimeiutAction ).

TimeoutAction:TTransactionAction —
действие, которое произойдет по истечении времени, определенного в TimeOut-commit, Roll back или commit-retaining.

TRParams:Tstrings
— параметры транзакции. Должны быть указаны до того, как стартует транзакция. Более подробно о параметрах транзакций можно узнать из руководства по IB API. По умолчанию транзакция стартует с параметрами:
isc_tpb_write
isc_tpb_concurrency
isc_tpb_wait
некоторые методы:

Commit — подтверждение изменений;
Rollback — откат изменений;
CommitRetaining — подтверждение изменений с сохранением состояния курсоров.

TFIBQuery — компонент для передачи серверу команд SQL и/или получения результата выполнения команд. Основное отличие от TQuery состоит в том, что TFIBQuery не является потомком TDataSet, в связи с чем визуализация данных затруднительна, хотя и возможна. После выполнения SQL-запроса TFIBQuery возвращает небуферированный, однонаправленный набор данных.
Свойство Database:TFIBDatabase — компонент TFIBDatabase, annioee?iaaiiue n AA, к которой направлен запрос.
Transaction:TFIBTransaction — транзакция, в контексте которой будут выполняться команды SQL.
Свойство SQL:TStrings хранит SQL-выражение, которое можно выполнить, вызвав метод ExecQuery . Возможно использование параметризуемых запросов — oiaaa свойство SQL должно быть, например,

Select * from myTable where myField = ? <parameter>
Где <parameter> — название параметра, может содержать алфавитно-цифровые латинские символы, а также "_" и "$". Вместо "?" возможно использование ":". К сожалению, в текущей версии FIBC нет design-time редактора параметров запроса, поэтому присвоить значение параметру можно только в ходе выполнения приложения, вызвав, например, Params.ByName ... Свойство RecordCount — текущее число записей, которые получил запрос (но не общее число записей, возвращаемых запросом!).

TFIBDataset — компонент наследник TDataSet. Это позволяет производить обработку набора данных с помощью data-aware компонент (TDBGrid или TDBEdit, например). Также, благодаря своему предку, TFIBDataSet может использоваться практически везде, где разработчик использует TQuery или TTable из поставки Delphi, например, при разработке многозвенных приложений.

Некоторые свойства:

SelectSQL, UpdateSQL, DeleteSQL, RefreshSQL, InsertSQL:TStrings —
содержат SQL выражения соответственно для выборки, редактирования, удаления, обновления и вставки записей. FIBC расширяет синтаксис SQL за счет использования OLD_ и NEW_ — соответственно старое и новое значения поля.
Например, если mytable состоит из трех столбцов (column1, column2, column3) и SelectSQL содержит:
Select * from mytable
то для того, чтобы была возможность редактировать Набор Данных, возвращаемых этим запросом, необходимо, чтобы UpdateSQL имел вид
Update mytable
set column1=?column1,
column2=?column2,
column3=?column3
where <expression>
где <expresion> — предикат, позволяющий однозначно определить запись таблицы mytable. Если, например, column1 содержит уникальные значения, то <expression> будет выглядеть так: column1=?old_column1.
Аналогично для RefreshSQL и DeleteSQL — обновляется/удаляется одна запись из набора данных.
DataSource:TdataSource — указывает на DataSorce главной таблицы. Служит для организации связи master-detail.
Большинство остальных свойств и методов схожи со свойствами TDataSet из поставки Delphi, поэтому подробно не рассматриваются.

TFIBSQLMonitor — компонент, позволяющий осуществить мониторинг команд DSQL, eioi?ua iieo?aao сервер IB io FIB-i?eei?aiey.

ПРИМЕР FIB-ПРИЛОЖЕНИЯ.


Пример работает с БД, скрипт для создания которой приведен ниже:
CREATE DATABASE "D:\Stat.gdb"
USER "SYSDBA" PASSWORD "masterkey"
PAGE_SIZE 1024
DEFAULT CHARACTER SET WIN1251;
/* Generator Definitions */
CREATE GENERATOR NO_GEN;
SET GENERATOR NO_GEN TO 0;
/* Table: BIOLIFE */
CREATE TABLE BIOLIFE (SPECIES_NO INTEGER NOT NULL,
CATEGORY VARCHAR(15),
COMMON_NAME VARCHAR(30),
SPECIES_NAME VARCHAR(40),
LENGTH__CM_ NUMERIC(8,2),
LENGTH_IN NUMERIC(8,2),
NOTES BLOB(80, 1),
GRAPHIC BLOB(80, 0),
CONSTRAINT PK_BIOLIFE PRIMARY KEY (SPECIES_NO));

Я же просто воспользовался утилитой Data Migration Wizard из поставки Delphi для переноса таблицы Biolife.db.
Поместим на форму компоненты TFIBDatabase, TFIBTransaction, TFIBDataset, TFIBQuery, TDataSourse, TDBNavigator, TDBGrid, TDBImage, TDBMemo, TOpenPictureDialog и три TBitButton.

Вид Формы на этапе проектирования:

TFIBQuery1 служит для получения уникального значения генератора при добавлении записей в таблицу Biolife, c которой ассоциирован FIBDataset1. Кнопки имеют названия: btLoad, btRollback, btCommit.

По нажатию btLoad происходит вызов диалога выбора рисунка, с последующим сохранением в БД.

btRollback и btCommit вызывают соответственно откат и подтверждение изменений в БД.

Вся инициализация свойств происходит в обработчике OnCreate формы (конечно, это можно было бы проделать в design-time). Обработчик события btLoad.OnClick мог бы выглядеть следующим образом:

procedure TForm1.btLoadClick(Sender: TObject);
begin
if OpenPictureDialog1.Execute then begin
DataSource1.Edit;
DBImage1.Picture.LoadFromFile(OpenPictureDialog1.FileName);
end;
end;

Файл, ассоциированный с формой, приведен ниже:
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
FIBQuery, StdCtrls, Buttons, Db, FIBDataSet, Grids, DBGrids, FIBDatabase,
DBCtrls, ExtCtrls, ExtDlgs;
type
TForm1 = class(TForm)
FIBDatabase1: TFIBDatabase;
FIBTransaction1: TFIBTransaction;
DBGrid1: TDBGrid;
DataSource1: TDataSource;
FIBDataSet1: TFIBDataSet;
btCommit: TBitBtn;
btRollback: TBitBtn;
FIBQuery1: TFIBQuery;
DBImage1: TDBImage;
DBMemo1: TDBMemo;
DBNavigator1: TDBNavigator;
btLoad: TBitBtn;
OpenPictureDialog1: TOpenPictureDialog;
procedure FormCreate(Sender: TObject);
procedure btCommitClick(Sender: TObject);
procedure btRollbackClick(Sender: TObject);
procedure FIBDataSet1BeforePost(DataSet: TDataSet);
procedure FIBDataSet1PostError(DataSet: TDataSet; E: EDatabaseError;
var Action: TDataAction);
procedure btLoadClick(Sender: TObject);
end;
var
Form1: TForm1;
implementation
{$R *.DFM}
procedure TForm1.FormCreate(Sender: TObject);
begin
with FIBDatabase1 do begin
Transaction:=FIBTransaction1;
DBParams.Clear;
DBName:='d:\stat.gdb';//путь к БД
DBParams.Add('lc_ctype=win1251'); //языковой драйвер
DBParams.Add('user_name=sysdba'); //пользователь
DBParams.Add('password=masterkey');//пароль
//DBparams.Add('role=default');//роль, если нужно
UseLoginPrompt:=false;//не запрашивать пароль
DefaultTransaction:=FIBTransaction1;//транзакция по умолчанию
try
Connected:=true;//открываем БД
except
showmessage('Ошибка открытия БД !');
Application.Terminate;
end;
end;

with FIBTransaction1 do begin
DefaultDatabase:=FIBDatabase1;//TFIBDatabase по умолчанию
TRParams.Clear;
TRParams.Add('write');
TRParams.Add('read_committed');
TRParams.Add('rec_version');
TRParams.Add('nowait');
Active:=true;//стартуем транзакцию
end;
with FIBDataSet1 do begin
Database:=FIBDatabase1;
with SelectSQL do begin
Clear;
Add('select * from BIOLIFE');
end;
with UpdateSQL do begin
Clear;
Add('update BIOLIFE');
Add('set');
Add('CATEGORY=?CATEGORY,');
Add('COMMON_NAME=?COMMON_NAME,');
Add('SPECIES_NAME=?SPECIES_NAME,');
Add('LENGTH__CM_=?LENGTH__CM_,');
Add('LENGTH_IN=?LENGTH_IN,');
Add('NOTES=?NOTES,');
Add('GRAPHIC=?GRAPHIC');
Add('where');
Add('SPECIES_NO=?OLD_SPECIES_NO');
end;
with InsertSQL do begin
Clear;
Add('insert into BIOLIFE (');
Add('SPECIES_NO,CATEGORY,');
Add('COMMON_NAME,SPECIES_NAME,');
Add('LENGTH__CM_,LENGTH_IN,');
Add('NOTES,GRAPHIC)');
Add('values (');
Add('?SPECIES_NO,?CATEGORY,');
Add('?COMMON_NAME,?SPECIES_NAME,');
Add('?LENGTH__CM_,?LENGTH_IN,');
Add('?NOTES,?GRAPHIC)');
end;
with RefreshSQL do begin
Clear;
Add('select * from BIOLIFE ');
Add('where SPECIES_NO=?OLD_SPECIES_NO');
end;
with DeleteSQL do begin
Clear;
Add('delete from BIOLIFE where');
Add('SPECIES_NO=?OLD_SPECIES_NO');
end;
Active:=true;
end;
with FIBQuery1 do begin
Database:=FIBDatabase1;
Transaction:=FIBTransaction1;
SQL.Clear;
SQL.Add('select gen_id(no_gen,1) from rdb$database');
end;
DataSource1.DataSet:=FIBDataSet1;
DBGrid1.DataSource:=DataSource1;
DBNavigator1.DataSource:=DataSource1;
DBImage1.DataSource:=DataSource1;
DBImage1.DataField:='GRAPHIC';
DBMemo1.DataSource:=DataSource1;
DBMemo1.DataField:='NOTES';
end;

procedure TForm1.btCommitClick(Sender: TObject);
begin
if (FIBDataSet1.State in [dsInsert,dsEdit]) then FIBDataSet1.Post;
FIBTransaction1.CommitRetaining;
end;

procedure TForm1.btRollbackClick(Sender: TObject);
begin
try
FIBDataSet1.DisableControls;
FIBTransaction1.Rollback;
FIBTransaction1.Active:=true;
FIBDataSet1.Active:=true;
finally
FIBDataSet1.EnableControls;
end;
end;

procedure TForm1.FIBDataSet1BeforePost(DataSet: TDataSet);
begin
if DataSet.State=dsInsert then begin
FIBQuery1.ExecQuery;
DataSet.Fields[0].AsInteger:=FIBQuery1.Fields[0].AsInteger;
FIBQuery1.Close;
end;
end;

procedure TForm1.FIBDataSet1PostError(DataSet: TDataSet; E: EDatabaseError;
var Action: TDataAction);
begin
DataSet.Cancel;
end;

procedure TForm1.btLoadClick(Sender: TObject);
var BLOBStream:TStream;
Fs:TMemoryStream;
begin

if OpenPictureDialog1.Execute then begin
FIBDataSet1.Edit;
fs:=TMemoryStream.Create;
BLOBStream:=FIBDataSet1.CreateBlobStream(FIBDataSet1.FieldByName('graphic'),bmReadWrite);
fs.LoadFromFile(OpenPictureDialog1.FileName);
fs.SaveToStream(BLOBStream);
BLOBStream.Free;
fs.free;
end;
end;

end.

Приложение на этапе выполнения:


Распространение FIB-приложений
:
кроме самого приложения:), необходимо установить клиента Interbase.

В поставку FIBC также входит документация, на основе которой и был подготовлен материал для данной статьи.

Александр Самусенко


© Компьютерная газета

полезные ссылки
Термокожухи для камер видеонаблюдения