Диалоговое окно настройки параметров
Рисунок 19.3. Диалоговое окно настройки параметров соединения на странице выбора провайдера
Первая страница Provider позволяет выбрать провайдер OLE DB для конкретного типа источника данных из числа провайдеров, установленных в системе. Здесь вы видите провайдеры не только для серверов БД, но и служб, установленных в операционной системе. Состав элементов управления следующих страниц зависит от типа источника данных, но различается не так уж сильно. Далее практически везде необходимо задать источник данных (имя сервера, базу данных, файл и т. д.), режим аутентификации пользователя, а также определить имя и пароль пользователя.
Рассмотрим процесс настройки на примере провайдера OLE DB для сервера Microsoft SQL Server.
Доступ к связанным наборам данных и командам ADO
Доступ к связанным наборам данных и командам ADO
Компонент TADOconnection обеспечивает доступ ко всем компонентам, которые используют его для доступа к хранилищу данных ADO. Все открытые таким образом наборы данных доступны через индексированное свойство
property DataSets[Index: Integer]: TCustomADODataSet;
Каждый элемент этого списка содержит дескриптор компонента доступа к данным ADO (тип TCustomADODataSet). Общее число связанных компонентов с наборами данных возвращается свойством
property DataSetCount: Integer;
Для этих компонентов можно централизованно установить тип используемого курсора при помощи свойства
type TCursorLocation = (clUseServer, clUseClient); property CursorLocation: TCursorLocation;
Значение clUseClient задает локальный курсор на стороне клиента, что позволяет выполнять любые операции с данными, в том числе не поддерживаемые сервером.
Значение cIUseServer задает курсор на сервере, который реализует только возможности сервера, но обеспечивает быструю обработку больших массивов данных.
Например:
for i := 0 to ADOConnection.DataSetCount — 1 do
begin
if ADOConnection.DataSets[i].Active = True then ADOConnection.DataSets[i].Close;
ADOConnection.DataSets[i].CursorLocation := clUseClient; end;
Помимо наборов данных компонент TADOConnection обеспечивает выполнение команд ADO. Команду ADO инкапсулирует специальный компонент TADOCommand, который рассматривается ниже. Все команды ADO, работающие с хранилищем данных через это соединение, доступны для управления через индексированное свойство
property Commands[Index: Integer]: TADOCommand
Каждый элемент этого списка представляет собой экземпляр класса
TADOCommand.
Общее число доступных команд возвращается свойством
property CommandCount: Integer
Например, сразу после открытия соединения можно выполнить все связанные команды ADO, реализовав таким образом нечто вроде скрипта:
procedure TForml.ADOConnectionConnectComplete(Connection: TADOConnection;
const Error: Error; var EventStatus: TEventStatus);
var i, ErrorCnt: Integer;
begin
if EventStatus = esOK then
for i := 0 to ADOConnection.CommandCount — 1 do
try if ADOConnection.Commands[i].CommandText <>
then ADOConnection.Commands[i].Execute; except
on E: Exception do Inc(ErrorCnt);
end;
end;
Однако компонент TADOConnection может выполнять команды ADO самостоятельно, без помощи других компонентов. Для этого используется перегружаемый метод
function Execute(const CommandText: WideString; ExecuteOptions:
TExecuteOptions = []): _RecordSet; overload;
procedure Execute(const CommandText: WideString;
var RecordsAffected:
Integer; ExecuteOptions: TExecuteOptions = [eoExecuteNoRecords]);
overload;
Выполнение команды осуществляется процедурой Execute (если команда не возвращает набор записей) или одноименной функцией Execute (если команда возвращает набор записей).
Параметр commandText должен содержать текст команды. Параметр RecordsAffected возвращает число обработанных командой записей (если они есть). Параметр
type
TExecuteOption = (eoAsyncExecute, eoAsyncFetch, eoAsyncFetchNonBlocking, eoExecuteNoRecords);
TExecuteOptions = set of TExecuteOption;
задает условия выполнения команды:
eoAsyncExecute — команда выполняется асинхронно (соединение не будет ожидать окончания выполнения команды, а продолжит работу, обработав сигнал о завершении команды, когда он поступит); eoAsyncFetch — команда получает необходимые записи также асинхронно; eoAsyncFetchNonBlocking — команда получает необходимые записи также асинхронно, но при этом созданная нить не блокируется; eoExecuteNoRecords — команда не должна возвращать записи.Если источник данных принял команду для выполнения и сообщил об этом соединению, вызывается метод-обработчик
TWillExecuteEvent = procedure(Connection: TADOConnection;
var CommandText: WideString; var CursorType: TCursorType; var LockType:
TADOLockType; var ExecuteOptions: TExecuteOptions;
var EventStatus:
TEventStatus; const Command: _Command;
const Recordset: _Recordset)
of object;
property OnWillExecute: TWillExecuteEvent;
После выполнения команды вызывается метод-обработчик
TExecuteCompleteEvent = procedure(Connection: TADOConnection; RecordsAffected: Integer;
const Error: Error; var EventStatus: TEventStatus;
const Command: _Command;
const Recordset: _Recordset) of object;
property OnExecuteComplete: TExecuteCompleteEvent;
Фильтрация
Фильтрация
Для фильтрации записей в наборе данных tbiindustry используется метод FiiterOnBookmark. Пользователь должен выбрать интересующие его записи в компоненте dbgindustry (он работает в режиме dgMuitiSelect). Затем, при нажатии кнопки tbFilter, созданные в свойстве SelectedRows компонента dbgindustry закладки передаются в массив Bookmarks типа TVarRec, который потом передается в качестве параметра метода FilterOnBookmark для фильтрации.
Массив Bookmarks служит здесь лишь промежуточным звеном для приведения типа закладок компонента dbgindustry к параметру метода FilterOnBookmark.
Главное окно приложения ADO Demo
Рисунок 19.9. Главное окно приложения ADO Demo
В качестве источника данных выберем файлы dBase, имеющиеся в демонстрационной базе данных Delphi \Program Files\Common Files\Borland Shared \Data. Для использования в приложении выберем две таблицы: INDUSTRY и MASTER. Они связаны между собой внешним ключом по полям IND_CODE и INDUSTRY соответственно.
Таблицу INDUSTRY можно редактировать, она инкапсулирована в компоненте tbiIndustry типа TADOTable и отображается в левом компоненте TDBGrid. А таблица MASTER инкапсулирована в компоненте tbIMaster, предназначена только для просмотра. Эти два компонента связаны отношением "ОДИН-КО-МНОГИМ" При помощи свойств MasterSource И MasterFields.
Листинг 19.2. Секция implementation модуля uMain приложения ADO Demo
implementation
uses IniFiles, FileCtrl;
const slniFileName: String = 'ADODemo.ini';
sEmptyDefDB: String = 'Database path is empty';
sEmptyFilter: String = 'Records for filter is not selected';
{$R *.dfm}
procedure TfmMain.FormShow(Sender: TObject);
begin
with TIniFile.Create(slniFileName) do
try
DefDBStr := ReaDString('DefDB', 'DefDBStr1, ");
edDefDB.Text := DefDBStr;
finally
Free; end;
SetLength(Bookmarks, 0);
end;
procedure TfmMain.FormClose(Sender: TObject; var Action: TCloseAction);
begin
with TIniFile.Create(slniFileName) do
try
WriteStringCDefDB', 'DefDBStr', edDefDB.Text);
finally
Free ;
end;
end;
procedure TfmMain.sbDefDBClick(Sender: TObject);
begin if SelectDirectory(DefDBStr, [], 0)
then edDefDB.Text := DefDBStr;
end;
procedure TfmMain.tbConnectClick(Sender: TObject);
begin
ADOConn.Close;
ADOConn.DefaultDatabase := ''; if DefDBStr = '' then
begin
MessageDlg(sEmptyDefDB, mtError, [mbOK], 0);
Abort;
end
else
begin
ADOConn.DefaultDatabase := DefDBStr;
ADOConn.Open;
end;
end;
procedure TfmMain.tbSaveClick(Sender: TObject);
begin
tbllndustry.UpdateBatch();
end;
procedure TfmMain.tbFilterClick(Sender: TObject);
var i: Integer;
begin
if dbglndustry.SelectedRows.Count > 0 then
begin
SetLength(Bookmarks, dbglndustry.SelectedRows.Count);
for i := 0 to dbglndustry.SelectedRows.Count — 1 do
begin
Bookmarks[i].VType := vtPointer;
Bookmarks[i].VPointer := pointer(dbglndustry.SelectedRows[i]);
end;
tbllndustry.FilterOnBookmarks(Bookmarks);
end else
MessageDlgtsEmptyFilter, mtWarning, [mbOK], 0);
end;
procedure TfmMain.tbUnFilterClick(Sender: TObject);
begin
tbllndustry.Filtered := False;
dbglndustry.SelectedRows.Clear;
end;
procedure TfmMain.dbglndustryTitleClick(Column: TColumn);
begin if tbllndustry.Active then
if (Pos(Column.FieldName, tbllndustry.Sort) > 0
}and(Pos('ASC', tbllndustry.Sort) > 0)
then tbllndustry.Sort := Column.FieldName + ' DESC' else tbllndustry.Sort := Column.FieldName + ' ASC';
end;
procedure TfmMain.ADOConnAfterConnect(Sender: TObject);
var i: Integer;
begin
for i := 0 to adoConn.DataSetCount - 1 do ADOConn.DataSets [i] .Open/end;
procedure TfmMain.ADOConnBeforeDisconnect(Sender: TObject);
var i: Integer;
begin
for i := 0 to adoConn.DataSetCount — 1 do ADOConn.DataSets[i].Close;
end;
end.
Групповые операции
Групповые операции
Компонент tbiindustry предназначен для выполнения групповых операций. Поэтому его свойство LociType имеет значение itBatchOptimistic. Для свойства CursorLocation установлено значение ciuseclient, чтобы обеспечить использование набора данных на клиенте. Тип курсора (свойство CursorType) должен быть ctstatic.
Сохранение изменений в хранилище данных обеспечивает метод updateBatch в методе-обработчике нажатия кнопки tbsave.
Иерархия классов компонента TADOCommand
Рисунок 19.8. Иерархия классов компонента TADOCommand
Так как компоненту TADOCommand нет необходимости обеспечивать работу набора записей, его непосредственным предком является класс TComponent. К его функциональности просто добавлен механизм соединения с БД через ADO и средства представления команды.
Команда передается в хранилище данных ADO через собственное соединение или через компонент TAOocormection, аналогично другим компонентам ADO (см. выше).
Текстовое представление выполняемой команды должно содержаться в свойстве
property CommandText: WideString;
Однако команду можно задать и другим способом. Прямая ссылка на нужный объект команды ADO может быть задана свойством
property CommandObject: _Command;
Тип команды определяется свойством
type TCommandType = (cmdUnknown, cmdText, cmdTable, cmdStoredProc, cmdFile, cmdTableDirect);
property CommandType: TCommandType;
Так как тип TCommandType также используется в классе TCustomADODataSet, где необходимо представлять все возможные виды команд, по отношению к компоненту TADOcommand этот тип обладает избыточностью. Здесь нельзя установить значения cmdTable, cmdFile, cmdTableDirect, а тип cmdStoredProc должен обозначать только те хранимые процедуры, которые не возвращают набор данных.
Если команда должна содержать текст запроса SQL, свойство CommandType должно иметь значение cmdText.
Для вызова хранимой процедуры необходимо задать тип cmdStoredProc, a в свойстве CommandText ввести имя процедуры.
Если для выполнения команды необходимо задать параметры, используется свойство
property Parameters: TParameters;
Выполнение команды осуществляется методом Execute:
function Execute: _RecordSet; overload;
function Execute(const Parameters: OleVariant): _Recordset;
overload;
function Execute(var RecordsAffected: Integer; var Parameters: OleVariant; ExecuteOptions: TExecuteOptions = []): _RecordSet; overload;
Разработчик может использовать любую из представленных нотаций перегружаемого метода:
параметр RecordsAffected возвращает число обработанных записей; параметр Parameters задает параметры команды; параметр ExecuteOptions определяет условия выполнения команды:TExecuteOption = (eoAsyncExecute, eoAsyncFetch, eoAsyncFetchNonBlocking, eoExecuteNoRecords); TExecuteOptions = set of TExecuteOption;
eoAsyncExecute — асинхронное выполнение команды;
eoAsyncFetch — асинхронная передача данных;
eoAsyncFetchNonBlocking — асинхронная передача данных без блокирования потока;
eoExecuteNoRecords — если команда возвращает набор записей, то они не передаются в компонент.
При работе с компонентом TADOConnection желательно использовать опцию eoExecuteNoRecords.
Для прерывания выполнения команды используется метод
procedure Cancel;
Текущее состояние команды можно определить свойством
type
TObjectState = (stClosed, stOpen, stConnecting, stExecuting, stFetching);
TObjectStates = set of TObjectState; property States: TObjectStates;
Иерархия классов наборов данных ADO
Рисунок 19.7. Иерархия классов наборов данных ADO
Компоненты ADO обладают обычным набором свойств и методов, а необходимый для доступа к данным через ADO механизм наследуют от своего общего предка — класса TCustomADODataSet. Кроме этого, класс TCustomADODataSet содержит ряд общих для всех потомков свойств и методов, рассмотреть которые будет очень полезно. Поэтому сначала мы изучим класс TCustomADODataSet и только потом перейдем к компонентам ADO.
Класс TCustomADODataSet
Класс TCustomADODataSet
Класс TCustomADODataSet инкапсулирует механизм доступа к хранилищу данных через ADO. Этот класс наполняет абстрактные методы общего предка TDataSet функциями конкретного механизма доступа к данным.
Поэтому здесь мы рассмотрим только уникальные свойства и методы класса TCustomADODataSet, обеспечивающие работу с ADO.
Соединение набора данных с хранилищем данных ADO осуществляется через компонент TADOConnection (свойство connection) или путем задания параметров соединения через свойство connectionstring (см. выше).
Команды
Команды
Программные средства ADO были бы неполными, если бы не имели возможности использовать для работы с данными язык SQL. Операторы DML и DDL, ряд специальных операторов ADO носят общее название текстовых команд.
Объект-команда инкапсулирует саму текстовую команду и механизм обработки и передачи команды. Объект команды выполняет следующие операции:
разбор текста команды; связывание команды с источником данных; оптимизацию команды; передачу команды источнику данных.Главный интерфейс объекта команды icommand имеет три метода:
function Cancel: HResult; stdcall;отменяет выполнение команды;
function Execute(const punkOuter: lUnknown; const riid: TGUID; var pParams: DBPARAMS; pcRowsAffected: PInteger; ppRowset: PlUnknown): HResult; stdcall;исполняет команду;
function GetDBSession(const riid: TGUID; out ppSession: lUnknown): HResult; stdcall;возвращает ссылку на интерфейс сессии, вызвавший данную команду.
Помимо основного, объект команды обеспечивает доступ к дополнительным интерфейсам:
ICommandPrepare — содержит два метода (Prepare И Unprepare) для подготовки команды; icommandProperties — задает для команды свойства, которые должны поддерживаться возвращаемым командой набором данных; iCommandText — управляет текстом команды (этот интерфейс обязателен для объекта команды); icommandwithParameters — обеспечивает работу с параметрами команды.Команды ADO
Команды ADO
Команде ADO, которой мы уделяли так много внимания в этой главе в VCL Delphi, соответствует компонент TADOCormand. Методы этого компонента во многом совпадают с методами класса TCustomADODataSet, хотя этот класс не является предком компонента (Рисунок 19.8). Он предназначен для выполнения команд, которые не возвращают наборы данных.
Компонент TADOConnection
Компонент TADOConnection
Компонент TADOConnection предназначен для управления соединением с объектами хранилища данных ADO. Он обеспечивает доступ к хранилищу данных компонентам ADO, инкапсулирующим набор данных (см. ниже).
Применение этого компонента дает разработчику ряд преимуществ:
все компоненты доступа к данным ADO обращаются к хранилищу данных через одно соединение; возможность напрямую задать объект провайдера соединения; доступ к объекту соединения ADO; возможность выполнять команды ADO; выполнение транзакций; расширенное управление соединением при помощи методов-обработчиков событий.Компонент TADODataSet
Компонент TADODataSet
Компонент TADODataSet предназначен для представления набора данных из хранилища данных ADO. Он прост в использовании, имея только несколько собственных свойств и методов, и применяет функции своего предка —класса TCustomADODataSet.
Это единственный компонент ADO, инкапсулирующий набор данных, для которого опубликованы свойства, позволяющие управлять командой ADO. Это свойства (см. выше)
property CommandText: WideString;
И
property CommandType: TCommandType;
В результате компонент представляет собой гибкий инструмент, который позволяет (в зависимости от типа команды и ее текста) получать данные из таблиц, запросов SQL, хранимых процедур, файлов и т. д. Например, вы выбираете нужное значение свойства CommandType = cmdText и заносите в свойство CommandText текст запроса SQL из редактора:
ADODataSet,CommandType = cmdText;
ADODataSet. CommandText := Memol.Lines.Text;
И запрос SQL готов к выполнению.
Примечание
Примечание
Для запросов SQL можно применять только язык Data Manipulation Language (использовать только SELECT).
Соединение с базой данных задается свойством Connectionstring или Connection (см. выше).
Набор данных открывается и закрывается свойством Active или методами Open и Close.
В приложениях компонент можно применять как все обычные компоненты доступа к данным, связывая инкапсулированный в нем набор данных с визуальными компонентами отображения данных через компонент TDataSource.
Компонент TADOQuery
Компонент TADOQuery
Компонент TADOQuery обеспечивает применение запросов SQL при работе с данными через ADO. По своей функциональности он подобен стандартному компоненту запроса (см. гл. 11).
Текст запроса задается свойством
property SQL: TStrings;
Параметры запроса определяются свойством
property Parameters: TParameters;
Если запрос должен возвращать набор данных, для его открытия используется свойство
property Active: Boolean;
или метод
procedure Open;
В противном случае достаточно использовать метод
function ExecSQL: Integer; ExecSQL
Число обработанных запросом записей возвращает свойство
property RowsAffected: Integer;
Компонент TADOStoredProc
Компонент TADOStoredProc
Компонент TADOStoredProc позволяет использовать в приложениях Delphi, обращающихся к данным через ADO, хранимые процедуры. Он подобен стандартному компоненту хранимой процедуры (см. гл. Л).
Имя хранимой процедуры определяется свойством
property ProcedureName: WideString;
Для определения входных и выходных параметров используется свойство
property Parameters: TParameters;
Если процедура будет применяться без изменений многократно, имеет смысл заранее подготовить ее выполнение на сервере. Для этого свойству
property Prepared: Boolean;
присваивается значение True.
Компонент TADOTable
Компонент TADOTable
Компонент ТАDOTаblе обеспечивает использование в приложениях Delphi таблиц БД, подключенных через провайдеры OLE DB. По своим функциональным возможностям и применению он подобен стандартному табличному компоненту (см. гл. 11).
Как вы уже знаете, в основе компонента лежит использование команды ADO, но ее свойства настроены заранее и изменению не подлежат.
Имя таблицы БД задается свойством
property TableName: WideString;
Другие свойства и методы компонента обеспечивают применение индексов (этой возможности лишен любой компонент запроса).
Так как не все провайдеры ADO обеспечивают прямое использование таблиц БД, то для доступа к ним может понадобиться запрос SQL. Если свойство
property TableDirect: Boolean;
имеет значение True, осуществляется прямой доступ к таблице. В противном случае компонент генерирует соответствующий запрос.
Свойство
property Readonly: Boolean;
позволяет включить или отключить для таблицы режим "только для чтения".
Компоненты ADO
Компоненты ADO
Компонент TADOConnection вобрал возможности перечислителя, источника данных и сессии с возможностями обслуживания транзакций.
Текстовые команды ADO реализованы в компоненте TADOCommand.
Наборы рядов (нотация Microsoft) можно получить при помощи компонентов TADOTable, TADOQuery, TAOostoredProc. Каждый из них реализует способ доступа к конкретному типу представления данных в хранилище. Далее по тексту, применительно к компонентам Delphi, совокупность возвращаемых из хранилища данных строк будем называть набором записей, что соответствует документации Inprise (см. www.borland.com или www.borland.ru) и стилю изложения предыдущих глав.
Набор свойств и методов компонентов ADO обеспечивает реализацию всех необходимых приложению БД функций. Способы использования компонентов ADO немногим отличаются от стандартных компонентов VCL доступа к данным (см. гл. 11).
Однако при необходимости разработчик может использовать все возможности интерфейсов ADO, обращаясь к ним через соответствующие объекты ADO. Ссылки на объекты имеются в компонентах (см. ниже).
Механизм соединения с хранилищем данных ADO
Механизм соединения с хранилищем данных ADO
Компоненты доступа к данным ADO могут использовать два варианта подключения к хранилищу данных. Это стандартный метод ADO и стандартный метод Delphi.
В первом случае компоненты используют свойство connectionstring для прямого обращения к хранилищу данных. Во втором случае используется специальный компонент TADOConnection, который обеспечивает расширенное управление соединением и позволяет обращаться к данным нескольким компонентам одновременно.
Свойство connectionstring предназначено для хранения информации о соединении с объектом ADO. В нем через точку с запятой перечисляются все необходимые параметры. Как минимум, это должны быть имена провайдера соединения или удаленного сервера:
Connectionstring:='Remote Server=ServerName;Provider=ProviderName';
При необходимости указываются путь к удаленному провайдеру:
Connectionstring:='Remote Provider=ProviderName';
и параметры, необходимые провайдеру:
'User Name=User_Name;Password=Password';
Каждый компонент, обращающийся к хранилищу данных ADO самостоятельно, задавая параметры соединения в свойстве Connectionstring, открывает собственное соединение. Чем больше приложение содержит компонентов ADO, тем больше соединений может быть открыто одновременно.
Поэтому целесообразно реализовать механизм соединения ADO через специальный компонент — TADOConnection. Этот компонент открывает соединение, также заданное свойством Connectionstring (см. выше), и предоставляет разработчику дополнительные средства управления соединением.
Компоненты, работающие с хранилищем данных ADO через данное соединение, подключаются к компоненту TADOConnection при помощи свойства
property Connection: TADOConnection;
которое имеет каждый компонент, инкапсулирующий набор данных ADO.
Наборы данных ADO
Наборы данных ADO
На странице ADO Палитры компонентов Delphi, кроме компонентов соединения есть стандартные компоненты, инкапсулирующие набор данных и адаптированные для работы с хранилищем данных ADO (Рисунок 19.7). Это компоненты:
TADODataSet — универсальный набор данных; TАоотаblе — таблица БД; TADOQuery — запрос SQL; TAoostoredProc — хранимая процедура.Как и положено для компонентов, инкапсулирующих набор данных, их общим предком является класс TDataSet, предоставляющий базовые функции управления набором данных (см. гл. II).
Наборы рядов
Наборы рядов
Объект-набор рядов является основным объектом ADO, обеспечивающим работу с данными. Он инкапсулирует совокупность рядов из источника данных, механизмы навигации по рядам и поддержания рядов в актуальном состоянии.
Объект сессии имеет обязательный интерфейс IOpenRowset с методом
function OpenRowset(const punkOuter: lUnknown; pTablelD: PDBID; plndexID: PDBID; const riid: TGUID; cPropertySets: UINT; rgPropertySets: PDBPropSetArray; ppRowset: PlUnknown): HResult; stdcall;
который открывает необходимый набор рядов.
В зависимости от возможностей источника данных набор рядов может поддерживать различные интерфейсы. Но пять из них являются обязательными:
IRowset — обеспечивает навигацию по рядам; IAccessor — обеспечивает представление информации о формате рядов, содержащихся в буфере набора рядов; IRowsetinfo — позволяет получить информацию о наборах рядов (например, число рядов или число обновленных рядов); Icoiumnsinfo — позволяет получить информацию о колонках рядов (наименование, тип данных, возможность обновления и т. д.); IconvertType — содержит единственный метод canConvert, позволяющий определить возможность преобразования типов данных в наборе рядов.
Примечание
Примечание
В отличие от привычной практики разработки интерфейсов в рамках модели СОМ, интерфейсы OLE DB часто имеют всего один-два метода. В результате большая группа интерфейсов реализует несколько вполне стандартных функций.
Дополнительные возможности по управлению набором рядов предоставляют следующие интерфейсы:
IRowsetchange — выполняет изменения в наборе рядов (вносит изменения, добавляет новые ряды, удаляет ряды и т. д.); IRowsetidentity — позволяет сравнивать ряды разных рядов; IRowsetindex — обеспечивает использование индексов; IRowsetLocate — выполняет поиск в наборе рядов; IRowsetupdate — реализует механизм кэширования изменений.Настройка соединения
Настройка соединения
Перед открытием соединения необходимо задать его параметры. Для этого предназначено свойство
property ConnectionString: WideString;
которое подробно рассматривалось в разд. "Компонент TADOConnection". Добавим лишь, что набор параметров изменяется в зависимости от типа провайдера и может настраиваться как вручную, так и при помощи специального редактора параметров соединения, который вызывается двойным щелчком на компоненте TADOConnection, перенесенным на форму, или щелчком на кнопке в поле редактирования свойства ConnectionString в Инспекторе объектов (Рисунок 19.2).
Объект ошибок ADO
Объект ошибок ADO
Все ошибки времени выполнения, возникающие при открытом соединении, сохраняются в специальном объекте ADO, инкапсулирующем коллекцию сообщений об ошибках. Доступ к объекту возможен через свойство
property Errors: Errors;
Подробнее об объекте ошибок ADO см. ниже.
Объект ошибок ADO
При рассказе о компонентах ADO в данной главе мы довольно часто упоминали об объектах ошибок ADO. Эти объекты содержат информацию об ошибке, возникшей при выполнении операции каким-либо объектом ADO.
В Delphi для объекта ошибки не предусмотрен специальный тип, но разработчик может использовать его методы интерфейса Error, предоставляемого многими методами других объектов ADO. Например, тип
TRecordsetEvent = procedure(DataSet: TCustomADODataSet; const Error: Error;
var EventStatus: TEventStatus) of object;
используемый для метода-обработчика, вызываемого после обновления набора данных, содержит параметр Error, дающий нам искомую ссылку.
Рассмотрим полезные свойства объекта ошибок ADO.
Свойство
property Description: WideString read Get_Description;
возвращает описание ошибки, переданное из объекта, в котором ошибка произошла.
Свойство
property SQLState: WideString read Get_SQLState;
содержит текст команды, вызвавшей ошибку. Свойство
property NativeError: Integer read Get_NativeError;
возвращает код ошибки, переданный из объекта, в котором ошибка произошла.
Объекты соединения с источниками данных
Объекты соединения с источниками данных
Внутренний механизм ADO, обеспечивающий соединение с хранилищем данных, использует два типа объектов. Это объекты-источники данных и объекты-сессии.
Объект-источник данных обеспечивает представление информации о требуемом реальном источнике данных и подключение к нему.
Для ввода сведений о хранилище данных используется интерфейс iDBProperties. Для успешного подключения необходимо задать обязательные сведения. Вероятно, для любого хранилища данных будет актуальной информация об его имени, пользователе и пароле. Однако каждый тип хранилища имеет собственные уникальные настройки. Для получения списка всех обязательных параметров соединения с данным хранилищем можно воспользоваться методом
function GetPropertylnfo(cPropertylDSets: UINT; rgPropertylDSets: PDBPropIDSetArray; var pcPropertylnfoSets: UINT; out prgPropertylnfoSets: PDBPropInfoSet; ppDescBuffer: PPOleStr): HResult; stdcall;
который возвращает заполненную структуру DBPROPINFO.
PDBPropInfo = ^TDBPropInfo;
DBPROPINFO = packed record
pwszDescription: PWideChar;
dwPropertylD: DBPROPID;
dwFlags: DBPROPFLAGS;
vtType: Word;
vValues: OleVariant;
end;
TDBPropInfo = DBPROPINFO;
Для каждого обязательного параметра в элементе dwFlags устанавливается значение DBPROPFLAGS_REQUIRED.
Для инициализации соединения необходимо использовать метод
function Initialize: HResult; stdcall;
интерфейса iDBinitiaiize объекта-источника данных.
Основы ADO
Основы ADO
Технология Microsoft ActiveX Data Objects обеспечивает универсальный доступ к источникам данных из приложений БД. Такую возможность предоставляют функции набора интерфейсов, созданные на основе общей модели объектов СОМ и описанные в спецификации OLE DB.
Технология ADO и интерфейсы OLE DB обеспечивают для приложений единый способ доступа к источникам данных различных типов (Рисунок 19.1). Например, приложение, использующее ADO, может применять одинаково сложные операции и к данным, хранящимся на корпоративном сервере SQL, и к электронным таблицам, и локальным СУБД. Запрос SQL, направленный любому источнику данных через ADO, будет выполнен.
Многие компоненты ADO, инкапсулирующие набор
Параметры
Многие компоненты ADO, инкапсулирующие набор записей, должны обеспечивать применение параметров запросов. Для этого в них используется специальный класс TParameters.
Для каждого параметра из коллекции класса TParameters создается отдельный класс TParameter.
Этот класс является наследником класса коллекции TCollection и инкапсулирует индексированный список отдельных параметров (см. ниже). Напомним, что для работы с параметрами обычных запросов в компонентах запросов и хранимых процедур используется класс TParams (например в компонентах dbExpress), также происходящий от класса коллекции.
Методы этих двух классов совпадают, а свойства имеют некоторые отличия. Для представления параметров команд в ADO имеется специальный объект параметров, который активно используется в процессе работы компонентов АDO, инкапсулирующих набор данных.
Поэтому для компонентов ADO в VCL был создан собственный класс параметров.
Перечислители
Перечислители
Объекты- перечислители обеспечивают поиск любых объектов ADO, которые имеют доступ к источникам данных. При этом другие перечислители также видны в данном перечислителе.
Первичный поиск источников данных осуществляется в провайдере ADO. Перечислители могут отбирать только источники данных конкретных типов, поэтому провайдер обеспечивает доступ к конкретному типу хранилища данных.
В составе ADO имеется системный корневой перечислитель, который выполняет начальный поиск других перечислителей и источников данных. Его можно использовать, зная его идентификатор класса CLSID_OLEDB_ENUMERATOR.
Примечание
Примечание
В Delphi GUID глобального перечислителя содержится в файле \Delphi7\Source \Vcl\OleDB.pas.
CLSID_OLEDB_ENrjMERATOR: TGUID= '{C8B522DO-5CF3-11CE-ADE5-OOAA0044773D}
Функции перечислителя содержатся в интерфейсе isourcesRowset. Метод
function GetSourcesRowset(const punkOuter: lUnknown; const riid: TGUID; cPropertySets: UINT; rgProperties: PDBPropSetArray; out ppSourcesRowset: lUnknown): HResult; stdcall;
возвращает ссылку на объект набора рядов (см. выше), содержащий сведения о найденных источниках данных или перечислителях.
Пример приложения ADO
Пример приложения ADO
Теперь попробуем применить на практике представленную в этой главе информацию о реализации ADO в Delphi. В качестве примера создадим простое приложение ADO Demo, которое "умеет" отображать пару таблиц БД, сохранять изменения при помощи групповых операций, сортировать записи и устанавливать фильтры на выбранные записи (Рисунок 19.9).
Провайдеры ADO
Провайдеры ADO
Провайдеры ADO обеспечивают соединение приложения, использующего данные через ADO, с источником данных (сервером SQL, локальной СУБД, файловой системой и т. д.). Для каждого типа хранилища данных должен существовать провайдер ADO.
Провайдер "знает" о местоположении хранилища данных и его содержании, умеет обращаться к данным с запросами и интерпретировать возвращаемую служебную информацию и результаты запросов с целью их передачи приложению.
Список установленных в данной операционной системе провайдеров доступен для выбора при установке соединения через компонент TADOConnection.
При инсталляции Microsoft ActiveX Data Objects в операционной системе устанавливаются следующие стандартные провайдеры.
Microsoft Jet OLE DB Provider обеспечивает соединение с данными СУБД Access при посредстве технологии ОАО. Microsoft OLE DB Provider for Microsoft Indexing Service обеспечивает доступ только для чтения к файлам и Internet-ресурсам Microsoft Indexing Service. Microsoft OLE DB Provider for Microsoft Active Directory Service обеспечивает доступ к ресурсам службы каталогов (Active Directory Service). Microsoft OLE DB Provider for Internet Publishing позволяет использовать ресурсы, предоставляемые Microsoft FrontPage, Microsoft Internet Information Server, HTTP-файлы. Microsoft Data Shaping Service for OLE DB позволяет использовать иерархические наборы данных. Microsoft OLE DB Simple Provider предназначен для организации доступа к источникам данных, поддерживающим только базисные возможности OLE DB. Microsoft OLE DB Provider for ODBC drivers обеспечивает доступ к данным, которые уже "прописаны" при помощи драйверов ODBC. Однако реальное использование столь экзотичных вариантов соединений представляется проблематичным. Драйверы ODBC и так славятся своей медлительностью, поэтому дополнительный слой сервисов здесь ни к чему. Microsoft OLE DB Provider for Oracle обеспечивает соединение с сервером Oracle. Microsoft OLE DB Provider for SQL Server обеспечивает соединение с сервером Microsoft SQL Server.Реализация ADO в Delphi
Реализация ADO в Delphi
Механизм доступа к данным через ADO и многочисленные объекты и интерфейсы реализованы в VCL Delphi в виде набора компонентов, расположенных на странице ADO. Все необходимые интерфейсы, обеспечивающие работу компонентов, объявлены и описаны в файлах OleDB.pas и ADODB.pas в папке \Delphi7\Source\Vcl.
Редактор настройки соединения ADO
Рисунок 19.2.Редактор настройки соединения ADO
Здесь можно настроить соединение через свойство ConnectionString (радиокнопка Use Connection String) или загрузить параметры соединения из файла с расширением udl (радиокнопка Use Data Link File).
Файл UDL (листинг 19.1) представляет собой обычный текстовый файл, в котором указывается название параметра и через знак равенства его значение. Параметры разделяются точкой с запятой.
Листинг 19.1 Демонстрационный файл DBDEMOS.UDL
[oledb]
Everything after this line is an OLE DB initstring
Provider=Microsoft.Jet.OLEDB.4.0;Data Source=C:\Program Files\Common Files\Borland Shared\Data\DBDEMOS.mdb
Если файл параметров соединения отсутствует, настройку придется осуществлять вручную. Для этого следует нажать кнопку Build. В результате появляется диалоговое окно Data Link Properties, в котором можно настроить параметры соединения вручную. Оно представляет собой четырехстраничный блокнот, позволяющий вам этап за этапом задать все необходимые параметры (Рисунок 19.3).
Технология ADO обеспечивает универсальный способ
Резюме
Технология ADO обеспечивает универсальный способ доступа к гетерогенным источникам данных. Благодаря тому, что функции ADO реализованы на основе интерфейсов OLE DB и СОМ, приложению для доступа к данным не требуется дополнительных библиотек, кроме инсталлированного ADO.
Компонент TADOConnection обеспечивает соединение с источниками данных через провайдеры OLE DB. Компоненты TADODataSet, TADOTable, TADOQuery, TADOStoredProc обеспечивают использование наборов записей в приложении. Свойства и методы компонентов позволяют создавать полнофункциональные приложения.
Компонент TADOCommand инкапсулирует текстовую команду ADO. В дополнение к стандартным возможностям работы с данными, из компонентов можно напрямую обращаться к необходимым объектам и интерфейсам ADO.
Сессия
Сессия
Из объекта-источника данных можно создавать объекты-сессии. Для этого используется метод
function CreateSession(const punkOuter: lUnknown; const riid: TGUID; out ppDBSession: lUnknown}: HResult; stdcall;
интерфейса iDBCreateSession. Сессия предназначена для обеспечения работы транзакций и наборов рядов.
Схема доступа к данным через ADO
Рисунок 19.1. Схема доступа к данным через ADO
Возникает вопрос: каким образом источники данных смогут выполнить этот запрос?
За серверы БД беспокоиться не стоит, обработка запросов SQL — это их основная обязанность. Но как быть с файловыми последовательностями, электронными таблицами, файлами электронной почты и т. д.? Здесь на помощь приходят механизмы ADO и интерфейсы OLE DB.
OLE DB представляет собой набор специализированных объектов СОМ, инкапсулирующих стандартные функции обработки данных, и специализированные функции конкретных источников данных и интерфейсов, обеспечивающих передачу данных между объектами.
Согласно терминологии ADO, любой источник данных (база данных, электронная таблица, файл) называется хранилищем данных, с которым при помощи провайдера данных взаимодействует приложение. Минимальный набор компонентов приложения может включать объект соединения, объект набора данных, объект процессора запросов.
Примечание
Примечание
Объекты OLE DB создаются и функционируют так же, как и другие объекты СОМ. Каждому объекту соответствует идентификатор класса CLSID, хранящийся в системном реестре. Для создания объекта используется метод CoCreateinstance и соответствующая фабрика класса. Объекту соответствует набор интерфейсов, к методам которых можно обращаться после создания объекта.
В результате приложение обращается не прямо к источнику данных, а к объекту OLE DB, который "умеет" представить данные (например, из файла электронной почты) в виде таблицы БД или результата выполнения запроса SQL.
Технология ADO в целом включает в себя не только сами объекты OLE DB, но и механизмы, обеспечивающие взаимодействие объектов с данными и приложениями. На этом уровне важнейшую роль играют провайдеры ADO, координирующие работу приложений с хранилищами данных различных типов.
Такая архитектура позволяет сделать набор объектов и интерфейсов открытым и расширяемым. Набор объектов и соответствующий провайдер может быть создан для любого хранилища данных без внесения изменений в исходную структуру ADO. При этом существенно расширяется само понятие данных — ведь можно разработать набор объектов и интерфейсов и для нетрадиционных табличных данных. Например, это могут быть графические данные геоинформационных систем, древовидные структуры из системных реестров, данные CASE-инструментов и т. д.
Так как технология ADO основана на стандартных интерфейсах СОМ, которые являются системным механизмом Windows, это сокращает общий объем работающего программного кода и позволяет распространять приложения БД без вспомогательных программ и библиотек.
Примечание
Примечание
Нижеследующее описание спецификации OLE DB представлено в соответствии с официальной терминологией Microsoft для данной предметной области.
Спецификация OLE DB различает следующие типы объектов, которые будут рассмотрены ниже.
Перечислитель (Enumerator) выполняет поиск источников данных или других перечислителей. Используется для обеспечения функционирования провайдеров ADO. Объект-источник данных (Data Source Object) представляет хранилище данных. Сессия (Session) объединяет совокупность объектов, обращающихся к одному хранилищу данных. Транзакция (Trasaction) инкапсулирует механизм выполнения транзакции. Команда (Command) содержит текст команды и обеспечивает ее выполнение. Командой может быть запрос SQL, обращение к таблице БД и т. д. Набор рядов (Rowset) представляет собой совокупность строк данных, являющихся результатом выполнения команды ADO. Объект-ошибка (Error) содержит информацию об исключительной ситуации.Рассмотрим функциональные возможности основных объектов и интерфейсов OLE DB.
Соединение с источником данных
Соединение с источником данных
Для связывания приложения с источником данных используем компонент TADOConnection и настроим соединения, щелкнув на кнопке свойства connectionstring в Инспекторе объектов.
Перейдя в редактор Data Link Properties, выберем провайдер Microsoft OLE DB Provider for OLE DB Drivers (см. Рисунок 19.3). Как правило, он имеется в операционной системе, если вы не предпринимали специальных усилий по его удалению.
Далее, на странице Connection (см. Рисунок 19.4) выберем радиокнопку Use data source name и в списке — файлы dBase. Для создания соединения с провайдером ODBC этого вполне достаточно.
Прокомментируем другие свойства компонента соединения ADO.
Свойство LoginPrompt должно иметь значение False, чтобы запретить показ диалога авторизации пользователя, ненужный для файлов dBase.
Свойство DefaultDatabase пока останется пустым. Мы применим его для указания пути к файлам базы данных, используя элементы пользовательского интерфейса приложения.
Свойство CursorLocation имеет значение ciuseclient, чтобы обеспечить использование курсоров наборов данных на стороне клиента.
Свойство ConnectOptions имеет значение по умолчанию coConnectUnspecified.
Это означает, что все команды будут выполняться синхронно — соединение будет ожидать ответ на каждую команду.
Для свойства Mode установим значение cmShareDenyNone, что запрещает другим соединениям устанавливать любые ограничения — ведь в данном случае мы не планируем многопользовательскую работу с источником данных.
Для открытия соединения после запуска приложения необходимо задать путь к хранилищу данных. Для этого предназначена кнопка и однострочный редактор на Панели управления. После выбора пути его значение заносится в переменную DefDBStr и в текст редактора edoefDB. Переменная используется для установления соединения. Для включения соединения необходимо нажать кнопку tbconnect. Ее метод-обработчик проверяет состояние переменной DefDBStr и заполняет свойство DefaultDatabase компонента соединения.
Примечание
Примечание
Так как во время настройки соединения выше мы не задавали путь к хранилищу данных, то свойство DefauitDatabase сработает. Иначе его значение будет перекрыто настройками свойства connectionString.
Открытие наборов данных ADO в приложении выполняется в методе-обработчике ADOConnAfterConnect, который вызывается после полного открытия соединения. Аналогичным образом наборы данных закрываются перед закрытием соединения в методе-обработчике ADOconnBeforeDisconnect.
Текущее значение пути к хранилищу данных сохраняется в файле DemoADO.ini и загружается при открытии приложения.
Сортировка
Сортировка
Сортировка создана также для набора данных tbiindustry. При щелчке на заголовке колонки компонента dbgindustry вызывается метод-обработчик dbgindustryTitieClick. В нем, в зависимости от текущего состояния свойства сортировки tbiindustry.sort (какое поле сортируется и в каком порядке), задается новое значение свойства sort.
Транзакции
Транзакции
Компонент TADOconnection позволяет выполнять транзакции. Методы
function BeginTrans: Integer;
procedure CommitTrans;
procedure RollbackTrans;
обеспечивают начало, фиксацию и откат транзакции соответственно. Методы-обработчики
TBeginTransCompleteEvent = procedure(Connection: TADOConnection;
TransactionLevel: Integer;
const Error: Error;
var EventStatus:
TEventStatus) of object;
property OnBeginTransComplete: TBeginTransCompleteEvent;
TConnectErrorEvent = procedure(Connection: TADOConnection;
Error: Error;
var EventStatus: TEventStatus) of object;
property OnCornmitTransComplete: TConnectErrorEvent;
вызываются после начала и фиксации транзакции. Свойство
type TIsolationLevel = (ilUnspecified, ilChaos, ilReadUncommitted, ilBrowse, ilCursorStability, ilReadCorranitted, ilRepeatableRead, ilSerializable, illsolated);
property IsolationLevel: TIsolationLevel;
позволяет задать уровень изоляции транзакции:
IlUnspecif led — уровень изоляции не задается; Iichaos — изменения более защищенных транзакций не перезаписываются данной транзакцией; IlReadUncommitted — незафиксированные изменения других транзакций видимы; IlBrowse — незафиксированные изменения других транзакций видимы; IlCursorStability — изменения других транзакций видимы только после фиксации; IlReadCommitted — изменения других транзакций видимы только после фиксации; IlRepeatableRead — изменения других транзакций не видимы, но доступны при обновлении данных; ISerializable — транзакция выполняется изолированно от других транзакций; Ilisolated — транзакция выполняется изолированно от других транзакций.Свойство
TXactAttribute = (xaCommitRetaining, xaAbortRetaining); property Attributes: TXactAttributes;
задает способ управления транзакциями при их фиксации и откате:
xaCommitRetaining — после фиксации очередной транзакции автоматически начинается выполнение новой; xaAbortRetaining — после отката очередной транзакции автоматически начинается выполнение новой.Транзакции
Управление транзакциями в OLE DB реализовано на двух уровнях. Во-первых, всеми необходимыми методами обладает объект сессии. Он имеет интерфейсы ITransaction, ITransactionJoin, ITransactionLocal, ITransactionObject.
Внутри сессии транзакция управляется интерфейсами ITransactionLocal, ItransactionSC, ITransaction и их методами StartTransaction, Commit, Rollback.
Во-вторых, для объекта сессии можно создать объект транзакции при помощи метода
function GetTransactionObject(ulTransactionLevel: UINT; out ppTransactionObject: ITransaction): HResult; stdcall;
интерфейса ITransactionObject, который возвращает ссылку на интерфейс объекта-транзакции.
Управление соединением
Управление соединением
Соединение с хранилищем данных ADO открывается и закрывается при помощи свойства
property Connected: Boolean;
или методов
procedure Open; overload;
procedure Openfconst UserlD: WideString; const Password: WideString); overload;
и
procedure Close;
Метод open является перегружаемым при необходимости использования удаленного или локального соединения. Для удаленного соединения применяется вариант с параметрами UserID и Password.
До и после открытия и закрытия соединения разработчик может использовать соответствующие стандартные методы-обработчики событий:
property BeforeConnect: TNotifyEvent;
property BeforeDisconnect: TNotifyEvent;
property AfterConnect: TNotifyEvent;
property AfterDisconnect: TNotifyEvent;
Кроме этого, компонент TADOConnection имеет дополнительные методы-обработчики. После получения подтверждения от провайдера о том, что соединение будет открыто, перед его реальным открытием вызывается метод
TWillConnectEvent = procedure(Connection: TADOConnection; var Connectionstring, UserlD, Password: WideString; var ConnectOptions: TConnectOption;
var EventStatus: TEventStatus) of object;
property OnWillConnect: TWillConnectEvent;
Параметр Connection содержит указатель на вызвавший обработчик компонент.
Параметры Connectionstring, userID и Password определяют строку параметров, имя и пароль пользователя.
Соединение может быть синхронным или асинхронным, что и определяется параметром ConnectOptions типа TConnectOption:
type TConnectOption = (coConnectUnspecified, coAsyncConnect);
coConnectunspecified — синхронное соединение всегда ожидает результат последнего запроса;
coAsyncConnect — асинхронное соединение может выполнять новые запросы, не дожидаясь ответа от предыдущих запросов.
Наконец, параметр Eventstatus позволяет определить успешность выполнения посланного запроса на соединение:
type
TEventStatus = (esOK, esErrorsOccured, esCantDeny, esCancel, esUnwantedEvent);
esOK — запрос на соединение выполнен успешно;
esErrorsOccured — в процессе выполнения запроса возникла ошибка;
esCantDeny — соединение не может быть прервано;
esCancel — соединение было прервано до открытия;
esUnwantedEvent — внутренний флаг ADO.
Например, в случае успешного соединения можно выбрать синхронный режим работы компонента:
procedure TForml.ADOConnectionWillConnect(Connection: TADOConnection;
var ConnectionString, UserlD, Password: WideString;
var ConnectOptions: TConnectOption;
var Eventstatus: TEventStatus);
begin if Eventstatus = esOK
then ConnectOptions := coConnectunspecified;
end;
Кстати, параметр синхронности/асинхронности можно также задать при помощи свойства
ConnectOptions property ConnectOptions: TConnectOption;
После открытия соединения для выполнения собственного кода можно использовать метод-обработчик
TConnectErrorEvent = procedure(Connection:
TADOConnection; Error: Error;
var Eventstatus: TEventStatus) of object;
property OnConnectComplete: TConnectErrorEvent;
Здесь, если в процессе открытия соединения возникла ошибка, параметр Eventstatus будет равен esErrorsOccured, а параметр Error содержит объект ошибки ADO.
Теперь перейдем к вспомогательным свойствам и методам компонента TADOConnection, обеспечивающим соединение.
Для ограничения времени открытия соединения для медленных каналов связи используется свойство
property ConnectionTimeout: Integer;
задающее время ожидания открытия соединения в секундах. По умолчанию оно равно 15 сек.
Также можно определить реакцию компонента на неиспользуемое соединение. Если через соединение не подключен ни один активный компонент, свойство
property KeepConnection: Boolean;
в значении True сохраняет соединение открытым. Иначе, после закрытия последнего связанного компонента ADO, соединение закрывается.
При необходимости провайдер соединения ADO определяется напрямую свойством
property Provider: WideString;
Имя источника данных по умолчанию задается свойством
property DefaultDatabase: WideString;
Но если этот же параметр указан в строке соединения, то он перекрывает собой значение свойства.
При необходимости прямой доступ к объекту соединения OLE DB обеспечивает свойство
property ConnectionObject: _Connection;
При открытии соединения необходимо вводить имя пользователя и его пароль. Появление стандартного диалога управляется свойством
property LoginPrompt: Boolean;
Без этого диалога для задания данных параметров можно использовать свойство Connectionstring, метод open (см. выше) или метод-обработчик
type TLoginEvent = procedure(Sender:TObject;
Username, Password: string)
of object;
property OnLogin: TLoginEvent;
Свойство
type TConnectMode = (cmUnknown, cmRead, cmWrite, cinReadWrite, cmShareDenyRead, cmShareDenyWrite, cmShareExclusive, cmShareDenyNone);
property Mode: TConnectMode;
задает доступные для соединения операции:
cmUnknown — разрешение неизвестно или не может быть установлено; cmRead — разрешение на чтение; cmwrite — разрешение на запись; cmReadWrite — разрешение на чтение и запись; cmshareDenyRead — разрешение на чтение для других соединений запрещено; cmshareoenywrite — разрешение на запись для других соединений запрещено; cmShareExciusive — разрешение на открытие для других соединений запрещено; cmshareDenyNone — открытие других соединений с разрешениями запрещено.