Компоненты доступа к данным БД

Источник: codingrus
Kest

Наборы данных

Таблицы БД располагаются на диске и являются физическими объектами. Для операций с данными, содержащимися в таблицах, используются наборы данных. В терминологии Delphi набор данных представляет собой совокупность записей, извлеченных из одной или нескольких таблиц БД. Набор данных является логической таблицей, над которой можно осуществлять определенные операции при выполнении приложения.


Замечание
В отличие от Delphi, во многих СУБД вместо термина набор данных употребляются термины выборка или таблица.

В Delphi для работы с наборами данных таблиц применяются компоненты Table, Query, UpdateSQL, DecisionQuery и StoredProc. Компонент StoredProc привлекается для вызова хранимых процедур при организации взаимодействия с удаленными БД, компонент UpdateSQL обеспечивает работу с каптированными изменениями в записях. Компонент DecisionQuery задействуется при построении систем принятия решений. Наиболее универсальными и, соответственно, часто используемыми являются компоненты Table и Query, определяющие наборы данных, их и рассмотрим в первую очередь.

Базовые возможности доступа к БД предоставляет класс TDataSet - коллекция строк таблицы, представляющий наборы данных в виде совокупности строк и столбцов (записей и полей). Этот класс обеспечивает основные средства навигации (перемещения) и редактирования наборов данных.

Компоненты Table и Query происходят от класса TDBDataSet - потомка класса TDataSet (через класс TBDEDataSet). Они имеют схожие характеристики и поведение, определяемые базовыми классами. Каждому из этих компонентов присущи свои особенности. В этой главе рассматриваются наиболее общие характеристики наборов данных. Большая часть свойств, методов и событий изучается на примере операций с наборами данных.

Расположение БД, с таблицами которой выполняются операции, указывает свойство DatabaseName типа string. Значением свойства является имя каталога, в котором находится БД (файлы ее таблиц), или псевдоним, ссылающийся на этот каталог. Если для БД определен псевдоним, то его можно выбрать через Инспектор объектов в выпадающем списке.

Замечание

Желательно задавать имя БД через псевдоним. Это заметно облегчает перенос приложения и файлов БД в иные каталоги и на другие компьютеры, т. к. для обеспечения работоспособности приложения после изменения расположения БД достаточно изменить название каталога, на который ссылается псевдоним БД.

Для компонента Table использование свойства DatabaseName является единственной возможностью указать расположение таблиц БД. Для компонента Query дополнительно можно отметить в SQL-запросе путь доступа к каждой таблице.

Замечание

При задании расположения БД программным способом набор данных предварительно необходимо закрыть, установив его свойству Active значение False. В противном случае генерируется исключительная ситуация.

Пример. Задание расположения БД.

Table1.Active := false;

Table1.DatabaseName := 'BDPlace';

Table2.Active := false;

Table2.DatabaseName := 'C:\SALE\BD';




Для набора данных Table1 таблицы БД размещены в каталоге, на который указывает псевдоним BDPlace. Таблицы БД набора данных Таblе2 расположены в каталоге C:\SALE\BD. Для определения и изменения псевдонима и его параметров удобно использовать такие программы, как Database Desktop и BDE Administrator, входящие в состав среды Delphi.

Пример. Перебор всех записей набора данных.

var i: integer;



Table1.First;

for i:=l to Tablel.RecordCount do

begin

// Здесь можно поместить операторы, выполняющие

// обработку очередной записи

Table1.Next;

end;




Перебор всех записей набора данных осуществляется в цикле, для чего переменная i цикла последовательно принимает значения от 1 до RecordCount. Перед началом цикла при помощи метода First выполняется переход к первой записи набора данных. В цикле для перемещения на следующую запись вызывается метод Next.

Для локальных таблиц dBase или Paradox составляющие набор данных записи последовательно нумеруются, причем отсчет начинается с единицы. Номер записи в наборе данных определяет свойство RecNo с типом Longint, которое доступно во время выполнения программы.

Пример. Определение номера текущей записи.

Editl.Text := IntToStr (Tablel.RecNo) ;




Замечание

При изменении порядка сортировки или фильтрации нумерация записей также изменяется

Для таблиц Paradox свойство RecNo можно использовать для перехода к требуемой записи, установив в качестве значения свойства ее номер.

Пример. Переход к записи с указанным номером.

Tablel.RecNo:=StrToInt(Editl.Text);




Здесь выполняется переход к записи, номер которой содержится в редакторе Editi. Указанная запись становится текущей.

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

• навигационный;

• реляционный.


Навигационный способ доступа заключается в обработке каждой отдельной записи набора данных. Этот способ обычно применяется для локальных БД или для удаленных БД небольшого размера. При использовании навигационного способа доступа каждый набор данных имеет невидимый указатель текущей записи. Указатель идентифицирует запись, с которой могут выполняться такие операции, как редактирование или удаление. Поля текущей записи доступны для просмотра. Например, компоненты DBEdit и DBText отображают содержимое соответствующих полей именно текущей записи. Компонент DBGrid отмечает текущую запись с помощью специального маркера.

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

Реляционный способ доступа основан на обработке группы записей. Если требуется обработать одну запись, все равно действия осуществляются над группой, состоящей из одной записи. При реляционном способе доступа привлекаются SQL-запросы, поэтому его также называют SQL-ориентированным. Реляционный способ доступа нацелен на работу с удаленными БД и для них является предпочтительным. Его также можно использовать и для локальных БД.

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

Учитывая характер функционирования Web-приложений для публикации БД в Интернете, целесообразно применять реляционный способ доступа. Для локальных сетей интернет возможно использование навигационного способа доступа.


2.2.2. Состояния наборов данных

Наборы данных могут находиться в открытом или закрытом состояниях, на что указывает свойство Active типа Boolean. Если свойству Active присвоено значение True, то набор данных открыт. Открытый компонент TаЫе содержит набор данных, соответствующий таблице, связанной с ним через свойство TableName. Для открытого компонента Query набор данных соответствует результатам выполнения SQL-запроса, содержащегося в свойстве SQL этого компонента. Если свойство Active имеет значение False (по умолчанию), то набор данных закрыт, и его связь с БД разорвана.

Если по каким-либо причинам открытие набора данных невозможно, то при попытке задать свойству Active значение True выдается сообщение об ошибке, а свойство Active сохраняет значение False. Одной из причин невозможности открытия набора данных может являться неправильное значение свойства TableName или SQL.

При смене каталога БД (свойство DataBaseName) или имени таблицы (свойство TableName) предварительно необходимо закрыть набор данных, определив свойству Active значение False, в противном случае вырабатывается исключительная ситуация.

Замечание

На этапе проектирования для наборов данных свойству Active автоматически присваивается значение False при изменении значений свойств DataBaseName, TableName или SQL.

Пример. Управление состоянием набора данных с помощью свойства Active.

procedure TForm1.ButtonlClick(Sender: TObject);

begin

Queryl.Active := false;

Queryl.SQL.Clear;

Queryl.SQL.Add('select * from testl.db');

Queryl.Active := true;

end;




Здесь для открытия и закрытия набора данных Queryl используется свойство Active.

Управлять состоянием набора данных можно также с помощью методов Open и close.

Процедура Open открывает набор данных, ее вызов эквивалентен заданию свойству Active значения True. При обращении к методу open генерируются события BeforeOpen и AfterOpen и, соответственно, вызываются процедуры - обработчики этих событий.

Процедура Close закрывает набор данных, ее вызов эквивалентен присвоению свойству Active значения False. При выполнении метода close вырабатываются события Beforeclose и Afterclose, а также вызываются процедуры-обработчики этих событий.

Пример. Управление состоянием набора данных с помощью методов Open и Close.

procedure TForml.Button2Click(Sender: TObject);

begin

Queryl.Close;

Queryl.SQL.Clear;

Queryl.SQL.Add('select * from test2.db');

Queryl.Open;

end;




В примере для открытия и закрытия набора данных Queryl используются методы Open и Close.


2.2.3. Доступ к полям

Каждое поле набора данных представляет собой отдельный столбец, для работы с которым в Delphi служат объект Field типа TField и объекты производных от него типов, например, TIntegerField, TFloatField или TStringFieid. Для доступа к этим объектам и к полям записей предусмотрены соответствующие свойства и методы, доступные при выполнении приложения.

Свойство FieldCount типа integer указывает количество полей набора данных. Это свойство доступно только для чтения. Количество полей набора данных может отличаться от физического числа полей таблицы БД, поскольку в набор данных не обязательно включаются все поля таблицы.

Значение свойства Fields [index: integer] типа TField представляет собой поле (столбец) набора данных. К отдельному полю можно обратиться, указав его номер index в массиве Fields, при этом номера полей находятся в пределах от нуля до FieidCount-1.

Пример. Чтение полей текущей записи.

procedure TForml.ButtonlClick (Sender: TObject);

var n: integer;

begin

for n := 0 to Tablel.FieidCount - 1 do

ListBoxl.Items.Add (Tablel.Fields[n].AsString);

end;




В примере содержимое каждого поля текущей записи интерпретируется как строковое значение и добавляется к списку ListBoxl.

Номер поля в наборе данных не является заведомо фиксированным и заранее известным числом и зависит от порядка полей в структуре таблицы БД, от текущего состава полей набора данных, а также от значений свойств некоторых визуальных компонентов, связанных с этим набором данных, например, сетки DBGrid. Так, при изменении порядка расположения столбцов в компоненте DBGrid соответственно изменяется очередность следования полей набора данных. В связи с этим обращение к какому-либо полю по его номеру в массиве полей может вызвать обращение совсем к другому полю. Поэтому для доступа к полям чаще используются методы FindField и FieldByName.

Функция FindFieid (const FieldName: String) : TField возвращает для набора данных поле, имя которого указывает параметр FieldName. В отличие от номера в массиве полей, имя поля более статично и изменяется реже. Кроме того, имя поля несет большую смысловую нагрузку, чем номер. Если заданное параметром FieldName поле не найдено, то метод FindField возвращает значение Null. На практике чаще используется метод FieldByName, который отличается от метода FindFieid тем, что если заданное поле не обнаружено, то генерируется исключительная ситуация.

Свойство Fields и методы FindField и FieldByName наиболее часто задействуются для доступа к значению поля текущей записи совместно с такими свойствами объекта Field, как AsString, Aslnteger, AsFloat или AsBoolean, которые позволяют обращаться к значению поля как к строковому, целочисленному, вещественному или логическому значению соответственно.

Пример. Чтение содержимого полей текущей записи.

Var x: integer;



Labell.Caption := Tablel.FieldByName('Name').AsString;

x : = Tablel.FieldByName('Number').Aslnteger;




Здесь строковое значение поля Name отображается в надписи Label1, а переменной х присваивается целочисленное значения поля Number. Если поле Number содержит значение, которое нельзя интерпретировать как целое число, это приводит к исключительной ситуации.

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

Пример. Изменение значений полей набора данных.

Var x: integer;



// Переключение набора данных в режим редактирования

Tablel. Edit;

// Изменение значения полей

Tablel. FieldByName ('Name') . AsString: =Edi tl. Text;

Tablel.FieldByName('Number').AsInteger:=x; // Сохранение изменений Tablel.Post;




Здесь после переключения набора данных Table1 в режим редактирования выполняется запись новых значений в поля Name и Number текущей записи. Внесенные изменения сохраняются, а набор данных возвращается в режим просмотра.


2.2.4. Особенности набора данных Table


Компонент Table представляет собой набор данных, который в некоторый момент времени может быть связан с одной таблицей БД. Набор данных, возвращаемый компонентом Table, получается на основе навигационного способа доступа к данным. Его рекомендуется использовать для локальных БД. При работе с удаленными БД следует применять компонент Query. В дальнейшем при рассмотрении вопросов, связанных с локальными БД, обычно будем использовать компонент Table.

Связь между таблицей и компонентом Table устанавливается через его свойство TableName типа TFiieName, которое определяет имя таблицы (и имя файла с данными таблицы). При задании значения свойства TableName указывается имя файла и его расширение.

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

Пример. Задание имени таблицы БД.

procedure TForml.ButtonlClick (Sender: TObject);

begin

if OpenDialogl.Execute then 

begin

Table1.Active := false;

Tablel.TabieName := OpenDialogl.FileName;

Tablel.Active := true; 

end;

end;




В примере нажатие кнопки Button1 приводит к появлению диалогового окна выбора имени файла. При выборе файла таблицы его имя фиксируется как значение свойства TableName. Набор данных Table1 предварительно закрывается и открывается после смены таблицы. Тип таблицы распознается автоматически по расширению. имени файла. При наличии ошибок, например, связанных с нарушением структуры таблицы, выдается соответствующее сообщение, а набор данных остается закрытым.

Свойство TаblеТуре типа TTtableType определяет тип таблицы. Для локальных таблиц это свойство может принимать следующие значения:

• ttDefault -- тип таблицы выявляется автоматически, исходя из расширения файла;

• ttParadox - таблица Paradox; П ttDBase - таблица dBase; О ttFoxPro - таблица FoxPro;

• ttAScii - текстовый файл, содержащий данные в табличном виде (ASCII-таблица).


Если свойство ТаblеТуре имеет значение ttDefault (по умолчанию), то тип таблицы определяется по расширению файла:

• DB или отсутствует - таблица Paradox;

• DBF - таблица dBase;

• ТХТ - текстовый файл (ASCII-таблица).


По умолчанию в состав набора данных Table попадают все записи связанной с ним таблицы. Для отбора записей, удовлетворяющих определенным условиям, можно использовать фильтрацию.


2.2.5. Особенности набора данных Query

Компонент Query представляет собой набор данных, записи которого формируются в результате выполнения SQL-запроса. Набор данных, возвращаемый компонентом Query, основан на реляционном способе доступа к данным. При работе с удаленными БД следует применять именно набор данных Query.



Рис. 2.5. Редактирование SQL-запроса

В отличие от компонента Tаblе, набор данных Query может включать в себя записи более чем одной таблицы БД.

Текст запроса, на основании которого в набор данных отбираются записи, содержится в свойстве SQL типа Tstrings. Запрос включает в себя команды на языке SQL и выполняется при открытии набора данных. Запрос также называют SQL-запросом или SQL-программой.

При формировании запроса на этапе разработки приложения можно использовать текстовый редактор (рис. 2.5), вызываемый через Инспектор объектов двойным щелчком кнопки мыши при размещении указателя на поле значения свойства SQL.

SQL-запрос также можно конструировать и модифицировать динамически, внося изменения в его текст (значение свойства SQL компонента Query) по ходу работы приложения.

Пример. Приложение - редактор SQL-запросов.

Рассмотрим приложение - простейший редактор, позволяющий подготавливать и выполнять SQL-запросы. На рис. 2.6 показана форма приложения в процессе его функционирования. Кроме визуальных компонентов форма содержит два компонента доступа к данным Query1 и DataSource1, которые при выполнении приложения на экране не видны.



Рис. 2.6. Редактор SQL-запросов

Редактирование SQL-запроса осуществляется с помощью элемента Memo1. Набранный в поле ввода запрос выполняется при нажатии кнопки Button1 с заголовком Выполнить. Результат выполнения запроса отображается в компоненте DBGrid1.

При наличии в тексте SQL-запроса ошибки генерируется исключительная ситуация и выдается сообщение об ошибке, а результат запроса оказывается не определен. При этом набор данных Query1 автоматически закрывается.

Значения свойств DataSet источника данных DataSource1 И DataSource сетки DBGrid1, с помощью которых организуется взаимодействие компонентов Query1, DataSource1 И DBGrid1, устанавливаются при создании формы. В последующих примерах приложений значения этих свойств задаются через Инспектор объектов, и соответствующие операторы, присваивающие свойствам необходимые значения, в модуле формы отсутствуют.

Ниже приведен код модуля uSQLEdit формы Form1 приложения.

unit uSQLEdit;;

interface

uses

Windows, Messages, SysUtils, Classes, Graphics, Controls,Forms, Dialogs, StdCtrls, Grids, DBGrids, Db, DBTables; 

type

TForm1 = class (TForm) 

Memo1: TMemo; 

DataSource1: TDataSource; 

Query1: TQuery;

DBGrid1: TDBGrid; 

Button1: TButton; 

Label1: TLabel; 

Label2: TLabel;

procedure FormCreate (Sender: TObject);

procedure Button1Click (Sender: TObject); 

private

{ Private declarations } 

public

{ Public declarations }

end;

var

Form1: TForml;

implementation 

{$R *.DFM}

procedure TForml.FormCreate (Sender: TObject); 

begin

DataSourcel.DataSet := Queryl;

DBGridl.DataSource := DataSourcel;

end;

procedure TForml.ButtonlClick (Sender: TObject);

begin

Queryl.Close;

Queryl.SQL.Assign (Memol.Lines);

Query1.Open;

end; 

end.




В приведенном примере метод Assign выполняет присваивание одного объекта другому, при этом объекты должны иметь совместимые типы. Применительно к списку строк (класс Tstrings), которому принадлежат свойства SQL компонента Query1 и Lines компонента Memo1, подобное присваивание означает копирование информации из одного списка в другой с заменой содержимого последнего. Если размеры списков (число элементов) не совпадают, то после замены количество элементов заменяемого списка становится равным числу элементов копируемого списка.

Компонент Query обеспечивает выполнение SQL-запроса и является набором данных, который образуется на основе этого запроса. Формирование набора данных осуществляется при активизации компонента Query вызовом метода open или заданием свойству Active значения True. В ряде случаев при выполнении SQL-запроса в получении набора данных нет необходимости, например, при удалении, вставке или модификации записей (средствами языка SQL). В этом случае предпочтительнее выполнять запрос компонента Query не его открытием, а вызовом метода ExecSQL. При работе в сети метод ExecSQL обеспечивает требуемую модификацию набора данных, не передавая в вызывающее приложение (компьютер) записи набора данных, что заметно снижает нагрузку на сеть.

Для локальных БД вместо компонента Table также можно использовать компонент Query. Если присвоить свойству SQL значение "SELECT * FROM NameTableBD", а свойству RequestLive константу True, то набор данных Query будет похож на набор данных Table. В приведенном значении NameTableBD является именем таблицы БД, которое для компонента Table задается в свойстве Tаblеnаmе. Однако набор данных Query не имеет системы индексов, в отличие от набора данных Table, поэтому к Query неприменимы методы, опирающиеся на индексацию.

Страница сайта http://test.interface.ru
Оригинал находится по адресу http://test.interface.ru/home.asp?artId=30054