Delphi и расширения ADO - Создание приложения для просмотра метаданных

ОГЛАВЛЕНИЕ

 

Создание приложения для просмотра метаданных

Итак, рассмотрим, как можно применить объекты ADOX в Delphi. В качестве иллюстрации создадим приложение, с помощью которого пользователь сможет:

  1. просматривать метаданные в виде «дерева» объектов;
  2. изучать свойства объектов базы данных;
  3. получать исходный текст хранимых процедур и представлений.

Для выполнения этой задачи создадим новый проект и поместим на главную форму будущего приложения следующие компоненты: TMainMenu, TTreeView, TMemo и TStatusBar. В первую очередь нам следует включить ссылку на библиотеку типов ADOX (она находится в файле MSADOX.DLL), поскольку ADOX не поддерживается в Delphi 5 на уровне компонентов. Для этого следует выбрать Project | Import Type Library главного меню среды разработки Delphi, а затем из списка доступных библиотек типов выбрать Microsoft ADO Ext. 2.1 for DDL and Security. Чтобы избежать конфликтов с именами уже имеющихся классов Delphi (например, TTable), следует переименовать классы ADOX, заменив имена на что-нибудь типа TADOXxxx. Затем нужно убрать отметку из опции Generate Component Wrapper — в данном случае нам нужен только файл *.pas, содержащий интерфейс для доступа к объектам ADOX, а затем нажать кнопку Create Unit. Это приведет к созданию файла ADOX_TLB.PAS, содержащего интерфейс к библиотеке типов ADOX. Создав этот файл, мы должны сослаться на него, а также на модуль ADODB в предложении Uses главного модуля нашего проекта.

Теперь мы готовы к написанию кода для создания объектов ADOX. Создадим пункт меню File | Open Catalog и в обработчике его события OnClick напишем следующий код:

procedure TForm1.OpenCatalog1Click(Sender: TObject);
begin
// Получить имя источника данных (DataSource Name) с помощью стандартной
// диалоговой панели Microsoft
DS := PromptDataSource(Application.Handle, '');
// Если пользователь выбрал источник данных
If DS <> '' Then
   begin
// просмотреть метаданные
    BrowseData(DS);
   end;
end;

Здесь мы использовали метод PromptDataSource, реализованный в модуле ADODB, чтобы вызвать стандартную диалоговую панель Data Link Properties. Если источник данных выбран, то вызывается процедура BrowseData. Назначение этой процедуры — отобразить с помощью компонента TreeView метаданные, извлеченные из базы данных. Текст этой процедуры таков:

procedure TForm1.BrowseData(DataSource: String);
var
RootNode   : TTreeNode;
OneNode    : TTreeNode;
SubNode    : TTreeNode;
I             : Integer;
OldCursor : TCursor;
begin
// Заменить стандартный курсор на песочные часы
OldCursor := Screen.Cursor;
Screen.Cursor := crHourglass;
StatusBar1.Panels[0].Text := 'Extracting metadata, please wait...';
// Очистить компонент TreeView
ClearTree;
// и Memo
Memo1.Lines.Clear;
Application.ProcessMessages;
// Соединиться с источником данных
Catalog._Set_ActiveConnection(DataSource);
RootNode := TreeView1.Items.Add(Nil, 'Catalog');
// Добавить таблицы
OneNode   := TreeView1.Items.AddChild(RootNode, 'Tables');
For I := 0 to Catalog.Tables.Count-1 do
   begin
    SubNode := TreeView1.Items.AddChild(OneNode, Catalog.Tables[I].Name);
// Добавить поля, индексы и ключи
    ProceedTables(Catalog.Tables[I], SubNode);
   end;
// Добавить представления
If CheckViews(Catalog) then
begin
   OneNode   := TreeView1.Items.AddChild(RootNode, 'Views');
   For I := 0 to Catalog.Views.Count-1 do
    begin
      SubNode := TreeView1.Items.AddChild(OneNode, Catalog.Views[I].Name);
    end;
end;
// Добавить процедуры
OneNode   := TreeView1.Items.AddChild(RootNode, 'Procedures');
For I := 0 to Catalog.Procedures.Count-1 do
   begin
    SubNode := TreeView1.Items.AddChild(OneNode, Catalog.Procedures[I].Name);
   end;
RootNode.Expand(False);
// Заменить курсор на стандартный и очистить панель состояния
Screen.Cursor := OldCursor;
StatusBar1.Panels[0].Text := '';
end;

Обратите внимание на то, что в приведенной процедуре имеются три цикла для просмотра коллекций Tables, Views и Procedures объекта Catalog. Каждый найденный объект помещен в определенную ветвь компонента TreeView1. Коллекция Tables содержит один или более объектов Table, свойствами которых являются коллекции Columns, Indexes и Keys, и их также следует просмотреть. Это делается с помощью процедуры ProceedTables:

procedure TForm1.ProceedTables(T: Table; N : TTreeNode);
var
I          : Integer;
SubNode : TTreeNode;
begin
// Добавить поля
If T.Columns.Count > 0 Then
SubNode := TreeView1.Items.AddChild(N, 'Columns');
For I := 0 to T.Columns.Count-1 do
   TreeView1.Items.AddChild(SubNode, T.Columns.Item[I].Name);
// Добавить индексы
If T.Indexes.Count > 0 Then
SubNode := TreeView1.Items.AddChild(N, 'Indexes');
For I := 0 to T.Indexes.Count-1 do
   TreeView1.Items.AddChild(SubNode, T.Indexes.Item[I].Name);
// Добавить ключи
If T.Keys.Count > 0 Then
SubNode := TreeView1.Items.AddChild(N, 'Keys');
For I := 0 to T.Keys.Count-1 do
   TreeView1.Items.AddChild(SubNode, T.Keys.Item[I].Name);
end;

И снова код содержит три цикла для просмотра коллекций Columns, Indexes и Keys объекта Table .

Вернемся к процедуре BrowseData. Отметим, что перед циклом просмотра коллекции Views следует выполнить проверку того, доступны ли представления для текущего источника данных:

   If CheckViews(Catalog) then ...

Это делается, чтобы избежать ошибок и исключительных ситуаций, которые могут возникнуть, если ADOX не поддерживает коллекцию Views для текущего источника данных. Исходный текст функции CheckView показан ниже:

   function CheckViews(C : _Catalog) : Boolean;
var
I : Integer;
begin
try
   I := C.Views.Count;
   CheckViews := True;
except
   CheckViews := False;
end;
end;

Теперь компонент TreeView1 заполнен метаданными. Для получения информации о конкретном объекте следует создать для этого компонента обработчик события OnChange. Вот его текст:

   procedure TForm1.TreeView1Change(Sender: TObject; Node: TTreeNode);
begin
If Node.Parent.Parent <> Nil Then
begin
   Case Node.Parent.Text[1] of
    'C' : ViewColumns(Node.Parent.Parent.Text, Node.Text);
    'I' : ViewIndexes(Node.Parent.Parent.Text, Node.Text);
    'K' : ViewKeys(Node.Parent.Parent.Text, Node.Text);
    'T' : ViewTables(Node.Text);
    'V' : ViewProps(Node.Text);
    'P' : ProcProps(Node.Text);
   end;
end;
end;

Как можно видеть, в этом обработчике события вызываются различные процедуры в зависимости от того, на какой из ветвей компонента TreeView1 пользователь щелкнул мышью. Например, процедура ViewTablesViewColumns, ViewIndexes и ViewKeys используются для изучения свойств полей, индексов и ключей. показывает число объектов внутри выбранной таблицы, а процедуры

Объекты Column, Index и Key обладают немалым количеством свойств, и в рамках данной статьи рассмотреть их подробно невозможно, поэтому в таблице 2 приведены их краткие описания.

Таблица 2

Column
Attributes Содержит характеристики поля
DefinedSize Содержит максимальный размер поля
NumericScale Содержит сведения о положении десятичной точки для числового поля
ParentCatalog Указывает на имя каталога, к которому принадлежит поле
Precision Содержит максимальную точность данных в поле
RelatedColumn Для ключевых полей содержит имя связанного поля
SortOrder Указывает порядок сортировки в данных для поля
Type Содержит тип данных, хранящихся в поле
Index
Clustered Указывает, является ли индекс кластерным
IndexNulls Указывает, как обрабатываются значения Null
PrimaryKey Указывает, реализует ли данный индекс первичный ключ
Unique Указывает, должен ли быть уникальным ключ, реализованный в данном индексе
Key
DeleteRule Указывает, каким образом обрабатывается удаление записи, содержащей первичный ключ
RelatedTable Для внешнего ключа указывает имя связанной таблицы
Type Содержит тип ключа
UpdateRule Указывает, как производится обновление записи, содержащей первичный ключ

Процедуры ViewProps и ProcProps предназначены для вывода исходного текста представлений и хранимых процедур. Рассмотрим, например, процедуру ProcProps, отображающую свойства хранимой процедуры:

   procedure TForm1.ProcProps(Name : String);
var
S          : String;
Disp      : IDispatch;
Command : _Command;
begin
S := 'PROCEDURE : ' + Catalog.Procedures.Item[Name].Name;
S := S + ^M^J + 'Created    : ' +
   VarToStr(Catalog.Procedures.Item[Name].DateCreated);
S := S + ^M^J + 'Modified   : ' +
   VarToStr(Catalog.Procedures.Item[Name].DateModified);
If CmdSupported(Catalog.Procedures.Item[Name]) Then
begin
   Disp := Catalog.Procedures.Item[Name].Get_Command;
   Command := Disp AS Command;
   S := S + ^M^J^M^J + Command.Get_CommandText;
end;
Memo1.Text := S;
end;

В вышеописанном коде мы использовали тот факт, что член коллекции Procedures в действительности указывает на объект ADO Command. Следовательно, мы можем использовать метод Get_Command для получения интерфейса IDispatch объекта Command и использовать их метод Get_CommandText для получения исходного текста хранимой процедуры.

Теперь мы знаем, как использовать объекты ADOX для извлечения и отображения метаданных. Еще одна возможность ADOX, которая будет кратко рассмотрена ниже, — создание баз данных и объектов внутри них без применения сложных DDL-запросов.