Каждая из версий Delphi приносит какие-либо новшества в работу с базами данных. Так, в Delphi 5 ярким примером такой новации может являться поддержка технологии ADO. В Delphi 6 также были включены многие новые возможности, в том числе и для работы с базами данных. А именно:
- в Delphi 6 добавлен принципиально новый механизм доступа к данным, называющийся dbExpress. Он обеспечивает исключительно быстрый и простой доступ к серверам баз данных;
- наборы данных в Delphi бегали поддерживать два новых типа полей::TFMTBCDFiefd и TSQLTimeStampField;
- добавлено несколько новых компонентов для упрощения работы с клиентскими наборами данных, а также с двухъярусными и многоярусными приложениями баз данных.
Рассмотрим перечисленные выше особенности Delphi 6 более подробно.
dbExpress представляет собой совокупность небольших по размеру драйверов, которые обеспечивают быстрый доступ к серверам баз данных, поддерживающих язык SQL. Список допустимых типов баз данных вы можете найти в табл. 3.1.Для каждой из баз данных dbExpress предоставляет определенный драйвер. Таким образом, если вы планируете распространять свое приложение, то в него нужно будет включить дополнительный файл драйвера, который представляет собой обычную библиотеку динамической компоновки (DLL).
Разберемся, какой из файлов библиотек вы должны будете включить в комплект поставки вашей программы. В таблице3.1 перечислены типы баз данных и библиотеки динамической компоновки, необходимые для работы с ними.
Таблица 3.1. Типы поддерживаемых баз данных
Тип базы данных
|
Имя файла
|
InterBase
|
DBEXPINT.DLL
|
DB2
|
DBEXPDB2.DLL
|
Orade
|
DBEXPORA.DLL
|
DBEXPMYS.DLL
|
Новый тип поля TFMTBCDField обеспечивает истинный двоично-десятичный формат поля. Напомним, что в Delphi 5использовался тип TBCDField, который хранил двоично-десятичные данные в формате Currency. Данный тип переводил данные формата Currency в BCD (Binary-Coded Decimal) инаоборот.
Другой новый тип поля TSQLTimeStampReld предназначен для поддержки времени и даты в формате, требуемом драйверам dbExpress.
Были добавлены три новых клиентских набора данных:
- TBDECIientDataSet;
- TSQLCIientDataSet;
- TIBCIientDataSet
Эти компоненты предназначены для простых приложений и объединяют в себе поставщик данных и набор данных. Если создаваемое приложение требует многократного обновления данных с сервера или использует отношение «главный—подчиненный» между таблицами, то лучше всего использовать вместо указанных клиентских наборов.данных внешний поставщик данных и отдельный клиентский набор данных.
Компонент TCIientDataSet в Delphi 6 обладает тремя новыми-свойствами:
- ConnectionBroker — применяется в случае, когда у вас в приложении имеется несколько наборов данных, которые задействуют одно и то же соединение с сервером базы данных. Данное свойство позволяет централизованно, с помощью изменения только одного значения, изменять значения свойства у всех наборов данных, использующих данное соединение;
- DisableStringTrim — позволяет контролировать ввод символов пробела в значениях, которые заносят пользователи в поля таблиц. Данное свойство имеет буле-выйтип. Если значение свойства — true, то данные сохраняются в поле таблицы в том виде, как их вводит пользователь, в ином случае все пробелы, вводимые пользователем, будут отсечены;
- XMLData — позволяет получить доступ из клиентского набора данных к XML-данным.
Новый набор компонентов позволяет вам работать с XML-документами. Мы их рассмотрим в последующем.
Кроме того, в Delphi 6 была реорганизована палитра компонентов. Компоненты, которые основаны на BDE (Borland Database Engine, процессор баз данных Borland), перемещены на отдельную закладку BDE. Добавлены новые закладки: InterBase Admin, dbExpress и DataSnap. Об этих закладках и их компонентах читайте далее в этой главе.
Среда Delphi 7 также привнесла изменения в работу с базами данных:
- Драйверы dbExpress теперь стали поддерживать Informix SE, Oracle 9i, DB2 7.2, InterBase 6.5 и MySQL 3.23.49. Кроме того, был добавлен новый драйвер для Microsoft SQL 2000.
- Корпорация Borland решила отказаться от использования SQL Links. Начиная с 2002 года SQL Links не будет развиваться и включаться в состав Delphi. Для реализации доступа к серверам баз данных SQL корпорацияBorland рекомендует использовать механизм dbExpress.
- Файл Borland Database Engine (BDEINST.CAB) больше не имеет цифровую подпись. Этот файл включается в поставку Delphi лишь для обеспечения совместимости программ, созданных в ранних версиях Delphi.
- Произошли изменения в некоторых компонентах для работы с базами данных и были добавлены новые:
- в свойстве DefauttRowsetSize компонентаTSQLDataSet (вкладка dbExpress) теперь установлено значение по умолчанию, давное 20;
- вместо компонента TSQLClientDataSet введен новый компонент TSimpteDataSet, находящийся на вкладкеdbExpress палитры компонентов.
Среда Delphi работает с таблицами баз данных, которые физически располагаются на диске. Поэтому такие таблицы мы будем называть физическими. Для доступа к данным, содержащимся в физических таблицах, применяются наборы данных.
Набором данных называется совокупность записей, выделенных по определенным правилам из одной или нескольких физических таблиц базы данных.
Набор данных по определению не будет представлять собой физическую таблипу, поэтому будем называть набор данных логической таблицей. Именно с логическими таблицами работает большинство из стандартных компонентовDelphi. Можно представлять себе взаимодействие физической и логической таблицы по аналогии, как физического файла и файловой переменной.
Итак, из всего вышесказанного можно сделать вывод, что нам при создании приложений баз данных придется работать в основном с наборами данных (или логическими таблицами).
Среда Delphi имеет несколько стандартных компонентов для работы с наборами данных. К их числу относятся такие компоненты, как Table, Query, StoredProc и другие. Работа со всеми этими компонентами будет подробно описана далее.
Доступ к данным в Delphi обеспечивает класс TDataSet, который представляет наборы данных в виде совокупности строк и столбцов. Строки являются записями, а столбцы — полями таблицы базы данных. Класс TDataSet обеспечивает возможность редактирования набора данных, а также предоставляет средства для перемещения (навигации) по записям. Многие из свойств, событии и методов класса TDataSet являются абстрактными. Они называются абстрактными, так как не могут быть использованы непосредственно классом TDataSet, а лишь в его классах-потомках.
Прямым потомком класса TDataSet является класс TBDEDataSet. Этот класс инкапсулирует в себе функциональные возможности Borland Database Engine (BDE) — процессора баз данных фирмы Borland.
BDE — это совокупность файлов динамических библиотек (DLL) и драйверов, которые отвечают за доступ к данным. Для более подробного знакомства с BDE обратитесь к занятию 4.
Класс TBDEDataSet имеет класс-потомок TDBDataSet, в котором определены дополнительные свойства и методы, обеспечивающие возможность связывания набора данных с физическими таблицами базы данных.
Далее мы рассмотрим два компонента Table и Query, которые являются потомками класса TDBDataSet Мы изучим их общие свойства на примерах операций с наборами данных. Эти компоненты расположены на закладке BDE палитрыкомпонентов Delphi 7.
Свойство Active имеет тип Boolean и позволяет открывать или закрывать набор данных. Его можно установить в окне инспектора объектов, но чаще всего такие операции с наборами данных производят во время выполнения приложения, например:
Более подробно о свойстве Active рассказывается ниже.
Свойство DatabaseName имеет тип String и задает полный путь к каталогу базы данных, например: ADatabaseVMyDBF.В значении этого свойства можно указать вместо пути к каталогу базы данных ее псевдоним.
Псевдоним (alias) представляет собой специальное имя для обозначения каталога базы данных и применяется для указания местонахождения файлов базы данных.
Более подробно о работе с псевдонимами мы расскажем на четвертом занятии.
Все существующие псевдонимы для баз данных будут показаны в окне инспектора объектов при щелчке левой кнопкой мыши на поле со списком напротив свойства DatabaseName.
Для компонента Table допустимо применение только свойства DatabaseName при задании пути к базе данных. КомпонентQuery имеет дополнительную возможность: в запросе SQL можно задать путь доступа к любой из таблиц базы данных.
Рассмотрим, как задается путь к нужной базе данных во время работы приложения:
- необходимо установить свойство Active компонента Table или Query в false (закрыть набор данных);
- затем указываем путь к базе данных либо ее псевдоним;
- после чего можно открыть набор Данных, присвоив свойству Active значение true:
Свойство TableName компонента Table имеет тип String и содержит имя текущей таблицы базы данных. В терминах Delphi каталог — это база данных, а файлы каталога — таблицы. Поэтому после указания пути к базе данных через свойство DatabaseName можно выбрать нужную таблицу из раскрывающегося списка свойства TableName в окне инспектора объектов (там будут отображены все названия файлов таблиц, находящихся в выбранном каталоге). Кроме того, значение этого свойства можно задавать и во время работы приложения, предварительно закрыв набор данных: Свойство RecordCount имеет тип Longint и содержит число записей, находящихся в текущий момент времени в наборе данных. Значение данного свойства не отображается в окне инспектора объектов — оно доступно только для чтения во время выполнения приложения. Строка выводит в компонент Editi количество записей набора данных Table1. Свойство RecNo имеет тип Longint и содержит номер текущей записи набора данных. Это свойство также доступно только для чтения во время работы приложения. Для перемещения по записям набора данных используются вызовы соответствующих методов: First, Last, Next, Prior и MoveBy: Если вы используете в своем приложении таблицы Paradox, то можно напрямую производить ввод чисел в свойство RecNo для перехода на нужную запись набора данных: Как мы уже видели ранее, наборы данных могут принимать два состояния: открытое или закрытое. При установке свойства Active в true набор данных будет открыт. Для закрытия набора данных нужно присвоить свойству Active значение false. Набор данных можно открыть как во время работы, так и во время создания приложения. В случае, когда открыть набор данных нельзя, генерируется исключительная ситуация и выдается сообщение об ошибке. Свойство Active при этом сохраняет значение false. Edit1. Text:=IntToStr(Tablel
.
RecordCount);
Table1
.
RecNo:=
15
:
// Переход на 15-ю запись набора данных
Кроме того, вы можете открыть набор данных с помощью вызова метода Open и закрыть с помощью методаClose:
Вызов этих методов имеет смысл, если вы хотите выполнить какие-либо действия перед открытием или после открытия набора данных, а также перед закрытием или после закрытия.
Итак, метод Open открывает набор данных. При вызове данного метода генерируются событияBeforeOpen и AfterOpen. Вы можете написать программы-обработчи¬ки этих событий. Это очень полезно, если вы хотите не открывать набор данных до тех пор, пока не выполнились какие-либо условия. Ниже представлен пример такого обработчика:
Примером использования события AfterOpen может служить приведенный ниже листинг:
Здесь после открытия набора данных выводится текстовое сообщение о готовности таблицы к работе. Имя таблицы содержится в свойстве TableName.
Метод Close закрывает набор данных. При его вызове генерируются события Before-Close иAfterClose.
Можно использовать обработчик события BeforeClose для вызова метода Post:
В данном примере сначала осуществляется проверка, в каком режиме находится набор данных Table1, при помощи значения свойства State. Если он находится в режиме вставки новой записи (dslnsert) или редактирования текущей записи (dsEdit), то перед закрытием набора данных все внесенные изменения сохраняются.
К обработке события AfterClose можно прибегать для выдачи пользователю сообщения о закрытии набора данных.
В примере использования события BeforeClose мы упомянули о режиме набора данных (свойствеState). Остановимся на этом немного подробнее. Наборы данных в разные моменты времени могут находиться в различных режимах, например неактивном, фильтрации данных, вставки, редактирования и т. д. Программист может читать значение свойства State, но изменять его напрямую нельзя. Для того чтобы перевести набор данных в один из режимов, нужно либо вызвать соответствующий метод, либо воспользоваться адекватными визуальными компонентами, речь о которых пойдет ниже.
Перечислим возможные режимы, в которых может находиться набор данных. Их всего тринадцать:
- dslnactive — неактивный. В этом режиме набор данных является закрытым и доступ к данным невозможен;
- dsBrowse — режим просмотра. Данный режим устанавливается по умолчанию для любого открытого набора данных. В этом режиме данные могут свободно просматриваться, но никаких изменений в них внести нельзя;
- dsEdit — режим редактирования. В этом режиме возможно только редактирование текущей (активной) записи набора данных;
- dslnsert — режим вставки. В данном состоянии активной является новая запись, которую можно редактировать, а затем либо принять изменения (post) либо отменить их (discard);
- dsSetKey — режим поиска, который доступен только для компонентов Table и ClientDataSet. В этом режиме происходит отбор записей, которые соответствуют некоторому критерию. Можно просматривать ограниченный набор данных (соответствующих критерию), но нельзя их редактировать или вставлять новые записи;
- dsCalcFнelds — расчет вычисляемых полей, в процессе которого невычисляемые поля таблицы не могут быть отредактированы и нельзя вставлять новые записи. Этот режим использует событие OnCalcFields;
- dsFilter — режим фильтра. В этом режиме показываются только те данные, которые соответствуют фильтру, при этом невозможно редактировать или вставлять записи. Режим использует событие OnFilterRecord;
- dsNewValue — режим доступа к свойству Newvalue. Данный режим является временным;
- dsOldValue — режим доступа к свойству OldValue. Также является временным;
- dsCurValue — режим доступа к свойству Curvalue. Как и предыдущие, временный режим;
- dsBlockRead — режим чтения блока данных. В этом режиме при переходе на следующую запись набора данных (при вызове метода Next) все визуальные компоненты, отображающие данные, не обновляются и не происходят никакие события;
- dsIntemalCalc — режим внутренних вычислений. Временный режим, в нем значения полей, свойствоTFIeld.ReldKind которых установлено в fklnternalCalc, вычисляются;
- dsOpening — режим открытия набора данных. Подразумевает состояние еще не завершенного открытия набора данных. Этот режим активируется, когда набор данных открывается для асинхронной выборки.
a:=Table1
.
FieldCount;
//а- переменная типа Integer
Свойство Fields имеет тип TFields и хранит список всех несоставных полей набора данных. Его можно представить себе в виде массива, который содержит поля набора данных, каждое под своим номером (индексом). Вы можете обращаться к конкретному полю набора данных при помощи указания его индекса(Index). Нумерация индексов начинается с нуля и заканчивается значением FieldCount-1. Если приложению известен тип данных конкретного поля, то его значение можно прочитать с помощью свойства Fields:
Edit1
.
Text:=Таble1
.
Fields
.
Fields[l].AsString;
Кроме того, допускается запись значения в нужное поле набора данных:
Вы, вероятно, обратили внимание на то, что при вставке в поле значения мы применили такое свойство объекта Field, как AsString. Данное свойство позволяет обращаться к содержимому поля как к строковому значению. Кроме рассмотренного свойства, имеются еще несколько:
- Aslnteger — обращение как к целой величине,
- AsFloat — как к вещественной,
- AsVariant — как к вариантной,
- AsCurrency — как к денежной,
- AsDateTime — как к «дате-времени» и
- AsBoolean — обращение как к логическому (булевому) значению.
Обращение к полям по их номеру не всегда эффективно, поскольку номер поля — величина не постоянная.
Номера полей зависят от многих факторов:
- от порядка полей в физической таблице базы данных,
- от состава полей набора данных в настоящий момент времени,
- от значений свойств визуальных компонентов.
Поэтому доступ к полю по его номеру чреват ошибками. На практике для доступа к полям разработчики чаще всего используют методы FindField и FieldByName.
Метод
FindField (
const
FleldName:
string
): TField;
обнаруживает поле по его имени.