M Y D E L P H I 7 . R U Самоучитель программирования  
 
  • Главная
  •  

     

    Интерфейс прикладного программирования ВDЕ

    Как уже говорилось выше, любое приложение Delphi, работающее с базами данных и написанное с использованием стандартных компонентов доступа к данным, обращается к данным и получает результат при помощи BDE. При этом механизм доступа к данным использует вызовы функций из API BDE.

    Достаточно сложно представить себе такую ситуацию, когда возникает необходимость создания приложения, использующего только функции BDE, без применения компонентов доступа к данным VCL. А вот отдельные функции вполне могут понадобиться в любой программе. Поэтому рассмотрим процесс работы приложения, использующего вызовы BDE, т. к. это дает хорошую возможность понять механизм доступа к данным, который реализован в Delphi.

    Итак, для создания приложения на основе вызовов функций BDE необходимо выполнить следующие операции:

    1. Инициализация BDE (функция DbiInit).

    2. Открытие объекта базы данных (функция DbiOpenDatabase).

    3. Определение рабочего каталога (функция obiSetDirectory), если на предыдущем этапе не задается псевдоним БД.

    4. Определение временного каталога (функция DbiSetPrivateoir).

    5. Открытие набора данных и создание курсора (функции DbOреnТаblе, DbiQExec и пр.; дескриптор курсора hDBICur).

    6. Заполнение структуры cuRProps, содержащей данные о курсоре и наборе данных (функция DbiGetCursorProps).

    7. Выделение памяти для буфера записи.

    8. Навигация набору данных (функции DbiSetToBegin, DbiSetToEnd, DbiSetToCursor и пр.)

    9. Чтение необходимой записи (функции DbiGetRelativeRecord,  DbiGetNextRecord, DbiGetRecord, DbiGetPriorRecord и др.).

    10. Чтение или обновление необходимого поля (функции DMGetFieid, DbiPutField).

    11. Освобождение всех ресурсов (освобождение буфера записи, закрытие курсора, таблицы, BDE).

    При использовании в программе функций из API BDE необходимо включить в секцию uses модуль BDE.

    В прикладном программировании задачи, которые требовали бы выполнения всех описанных выше операций, практически не встречаются. Между тем, включение в программный код отдельных функций API BDE оправдано. В качестве примера рассмотрим приложение, которое позволяет очистить таблицу базы данных (рис. 16.4).

    Дело в том, что при удалении записи из таблицы локальной СУБД (например Paradox) размер файла таблицы остается прежним, даже если удалить все записи. То есть на самом деле запись не удаляется, а только становится недоступной. При интенсивном использовании базы данных файлы таблиц могут занимать значительные объемы дискового пространства при довольно умеренном числе записей.

    Рис. 16.4. Главная форма проекта BDEEmptyTable

    Полная очистка таблиц базы данных осуществляется функцией DbiErr.ptyTable из API BDE. Именно она используется в демонстрационном приложении для радикального уменьшения размера таблиц.

    Примечание 

    Функция DbiEmptyTable используется в методе EmptyTable компонентов доступа к данным (см. гл. 17).

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

     Листинг 16.1. Модуль главной формы приложения BDEEmptyTable 

    unit Main; 

    interface

    uses

    Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, 

    StdCtrls, BDE, ExtCtrls, DBCtrls, Grids, DBGrids, Db, DBTables, Buttons;

    type

    TMainForm = class(TForm)

    AliasesList: TComboBox;

    TablesList: TComboBox;

    EmptyBtn: TBitBtn;

    Labell: TLabel;

    Label2: TLabel;

    procedure FormClose(Sender: TObject; var Action: TCloseAction);

    procedure FormShow(Sender: TObject);

    procedure AliasesListChange(Sender: TObject);

    procedure EmptyBtnClick(Sender: TObject); private

    hDB: hDBIDB;

    hCursor: hDBICur;

    DBDesc: DBDesc;

    TblDesc : TBLBaseDesc;

     public

    { Public declarations } 

    end;

    var

    MainForm: TMainForm;

    implementation 

    {$R *.DFM}

    procedure TMainForm.FormShow(Sender: TObject); 

    var Rslt: DBIResult;

     begin

    AliasesList.Items.Clear;

     TablesList.Items.Clear; hDB := Nil; 

    try

    DbiInit(Nil); // Инициалы BDE

     BDE DbiOpenDatabaseList(hCursor) ;

     repeat

    Rslt:= DbiGetNextRecord(hCursor, dbiNOLOCK, @DBDesc, nil) ;

     if (Rslt 0 DBIERR_EOF) then

    AliasesList.Items.Add(StrPas(DBDesc.szName));

     until (rslt <> DBIERR_NONE); DbiCloseCursor(hCursor) ;

     except

    on E:EDBEngineError do ShowMessage ('OiiMSKa MHMunajiM3auMM BDE');

    end; 

    end;

    procedure TMainForm.FormClose(Sender: TObject;

     var Action: TCloseAction); 

    begin

     try

    finally

    if hDB <> Nil then DbiCloseDatabase(hDB);// Закрытие базы данных

     DbiExit; // Закрытие сеанса работы с ВОЕ 

    end

     end;

    procedure TMainForm.AliasesListChange(Sender: TObject); 

    begin

     try

    if hDB <> Nil

    then DbiCloseDatabase(hDB);// Закрытие базы данных 

    DbiOpenDatabase // Открытие базы данных 

    (

    PChar(AliasesList.Text), // Псевдоним базы данных 

    Nil, // Тип базы данных 

    dbiReadWrite, // Режим редактирования данных

     dbiOpenShared, // Режим разделения данных

     Nil, // Пароль

    0, // Число дополнительных параметров 

    Nil, // Перечень полей для доп. параметров Nil, 

    // Список доп. параметров hDB 

    // Дескриптор базы данных 

    );

    DbiSetPrivateDir('с:\temp');// Определение временного каталога

    DbiOpenTableList(hDb, False, False, '*.DB', hCursor);

    TablesList.Items.Clear;

    TablesList.Clear;

    while DbiGetNextRecord(hCursor, dbiNOLOCK, @TblDesc, nil) = dbiErr_None

    do TablesList.Items.Add(TblDesc.szName);

     DbiCloseCursor(hCursor);

     except

    on E:EDBEngineError do ShowMessage('Ошибка открытия базы данных');

     end;

     end;

    procedure TMainForm.EmptyBtnClick(Sender: TObject); 

    begin

    try

    DbiEmptyTable(hDB, Nil, PChar(TablesList.Text), '');

    except

    on E:EDBEngineError do ShowMessage('Неверно задана таблица'}; 

    end; 

    end;

    end.

    При открытии главной формы (метод-обработчик FormShow) функция Dbiinit осуществляет инициализацию BDE. Затем функция DbiOpenDatabaseList создает в памяти временную таблицу, в которую записываются характеристики каждой зарегистрированной базы данных. Для этого применяется структура DBDesc. Курсор hcursor обеспечивает доступ к записям о базах данных.

    После этого функция DbiGetNextRecord позволяет осуществить последовательное считывание имен псевдонимов баз данных (для этого в параметре передается указатель на структуру DBDesс) и их запись в список компонента AliasesList типа TComboBox.

    При выборе из этого списка конкретного псевдонима работает метод-обработчик AliasesListchange. В нем открывается соответствующая база данных (функция DbiOpenDatabase), доступ к которой в дальнейшем осуществляется через дескриптор hDB.

    Функция DbiopenTableList создает временную таблицу в памяти, в которую помещаются данные о таблицах выбранной базы данных в соответствии с форматом структуры TBLBaseDesс. Функция DbiGetNextRecord позволяет передать эту информацию в список компонента TablesList типа TCombоВох.

    При щелчке на кнопке EmptyBtn в методе-обработчике EmptyBtndick работает функция DbiEmptyTabie, которая очищает выбранную ранее в компоненте TablesList таблицу.

    Теперь рассмотрим пример простейшего приложения, которое может отображать два поля из таблицы COUNTRY. DВ в демонстрационной базе данных DBDEMOS. Эта база данных поставляется в комплекте Delphi. В примере использованы только функции API BDE.

    Проект называется DirectBDE и имеет только одну форму, в которой отображаются сведения из таблицы COUNTRY. DB о государствах и их столицах (рис. 16.5). Кнопки в нижней части формы позволяют перемещаться по набору данных.

     Листинг 16.2. Модуль главной формы приложения DirectBDE 

    unit Unitl; 

    interface

    uses

    Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,

     StdCtrls, Buttons, BDE, ExtCtrls;

    type

    TMainForm = class(TForm)

    PriorBtn: TBitBtn;

    Panel2: ТPanel;:

    NextBtn: TBitBtn;

    Label3: ТLabel;

    CountryEdit: TEdit;

    Label1: TLabel;

    CapitalEdit: TEdit;

    procedure PriorBtnClick(Sender: TObject);

    procedure FormShow(Sender: TObject};

    procedure FormClose(Sender: TObject;

     var Action: TCloseAction);

    procedure NextBtnClick(Sender: TObject); 

    private

    hDB: hDBIDB;

    hCur: hDBICur;

    CursProps: CurProps;

    RecBuf: pByte;

    FValue: array [0 .. 255] of Char;

    IsEmpty: Bool;

    procedure OnBDEError;

     public

     end;

    var

    MainForm: TMainForm;

    implementation ($R *.DFM}

    procedure TMainForm.OnBDEError;

    var ErrInfo: dbiErrlnfo; // Структура, содержащая информацию об ошибках

    AStr: String; 

    begin

    DbiGetErrorlnfo(True, Errlnfo);// Функция возвращает информацию об ошибке c

    ase Errlnfo.iError of

    9733: AStr := 'Для создания записи недостаточно параметров'; 

    10024: AStr := 'Ошибка доступа к данным'; 

    10245: AStr := 'База данных занята другим пользователем';

     10038: AStr := 'Значение поля задано неверно';

    11871: AStr := 'Несоответствие типов';

    11959: AStr := 'В выражении отсутствует оператор GROUP BY';

     else

    AStr := 'Ошибочная операция с данными'; 

    end;

    ShowMessage(AStr) ; 

    end;

    procedure TMainForm.FormShow(Sender: TObject);

     begin

    hDB := Nil; hCur := Nil;

    Dbilnit(Nil); // Инициализация системы 

    BDE DbiOpenDatabase // Открытие базы данных 

    (

    'DBDEMOS', // Псевдоним базы данных

    Nil, // Тип базы данных

    dbiReadWrite, // Режим редактирования данных

    dbiOpenShared, // Режим разделения данных

    Nil, // Пароль

    0, // Число дополнительных параметров

    Nil, // Перечень полей для доп. параметров

    Nil, // Список доп. параметров

    hDB // Дескриптор базы данных

    );

    DbiSetPrivateDir('с:\temp'); // Определение временного каталога

    DbiOpenTable // Открытие таблицы

    (

    hDB, // Дескриптор базы данных 

    PChar('COUNTRY'), // Название таблицы

    PChar(szParadox), // Тип таблицы (только для локальных БД)

     Nil, // Название индекса (необязательный)

     Nil, // indexTagName — только для dBASE 

    0, // 0 — использовать первичный индекс 

    dbiReadWrite, // Режим редактирования данных

     dbiOpenShared, // Режим разделения данных

     xltField, // Режим трансляции данных

    False, // Признак одностороннего перемещения курсора

     Nil, // Дополнительные параметры

     hCur // Дескриптор курсора таблицы );

    DbiGetCursorProps // Определение параметров курсора 

    hCur, // Дескриптор курсора таблицы

    CursProps // Структура параметров курсора

     );

    GetMem // Вьщеление памяти под буфер записи 

    (

    RecBuf,

    CursProps.iRecbufSize*SizeOf(Byte) );

    DbiSetToBegin(hCur); // Установка курсора в начало набора данных

     DbiGetNextRecord // Перемещение на первую запись

     (

    hCur, // Дескриптор курсора таблицы 

    dbiNoLock, // Режим ограничения доступа

     RecBuf, // Буфер записи 

    Nil // Параметры записи );

    DbiGetField // Получение значения поля

     (

    hCur, // Дескриптор курсора таблицы 

    1, // Номер поля в структуре таблицы 

    RecBuf, // Буфер записи

    @FValue, // Переменная, в которую передается значение

     IsEmpty // Признак пустой ячейки );

    MainForm.CountryEdit.Text := FValue;

     DbiGetField(hCur, 2, RecBuf, @FValue, IsEmpty);

     MainForm.CapitalEdit.Text := FValue;

     end;

    procedure TMainForm.FormClose(Sender: TObject; 

    var Action: TCloseAction);

     begin try

    finally

    FreeMem(RecBuf); // Освобождение памяти буфера записи DbiCloseCursor(hCur); // Закрытие курсора 

    DbiCloseDatabase(hDB); // Закрытие базы данных

     DbiExit; // Закрытие сеанса работы с ВОЕ

    end 

    end;

    procedure TMainForm.PriorBtnClick(Sender: TObject);

    begin

    try

    if DbiGetPriorRecord(hCur, dbiNoLock, RecBuf, Nil) = DBIERR_BOF

    then PriorBtn.Enabled := False

    else 

    begin

    if Not NextBtn.Enabled then NextBtn.Enabled := True;

     DbiGetField{hCur, 1, RecBuf, SFValue, IsEmpty); 

    MainForm.CountryEdit.Text := FValue;

     DbiGetField(hCur, 2, RecBuf, @FValue, IsEmpty);

     MainForm.CapitalEdit.Text := FValue; 

    end; 

    except

    OnBDEError; 

    end;

     end;

    procedure TMainForm.NextBtnClick(Sender: TObject);

     begin 

    try

    if DbiGetNextRecord(hCur, dbiNoLock, RecBuf, Nil)=DBIERR_EOF

     then NextBtn.Enabled := False

     else

    begin

    if Not PriorBtn.Enabled then PriorBtn.Enabled := True;

     DbiGetFieldfhCur, 1, RecBuf, @FValue, IsEmpty); 

    MainForm.CountryEdit.Text := FValue;

    DbiGetField(hCur, 2, RecBuf, @FValue, IsEmpty);

     MainForm.CapitalEdit.Text := FValue;

     end; 

    except

    OnBDEError; 

    end;

     end;

    end.

    Рис. 16.5. Главная форма проекта DirectBDE

    При показе главной формы приложения в процедуре Formshow проводится инициализация BDE, открытие базы данных и таблицы. При этом создаются дескрипторы базы данных hDB и курсора таблицы hour, которые играют в дальнейшей работе приложения важную роль. Если при создании базы данных не указывать псевдоним БД, то обязательно нужно определить рабочий каталог базы данных с помощью функции DbiSetoirectory.

    После этого отводится память под буфер записи, в который будут передаваться значения полей текущей строки таблицы. Размер буфера определяется при помощи Структуры CURPropS.

    Затем курсор устанавливается на начало набора данных и на первую запись и осуществляется чтение значений двух полей таблицы.

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

    При закрытии формы проводятся операции по освобождению памяти буфера записи, закрытию базы данных и BDE.