Абстрактный набор данных
В основе иерархии классов, обеспечивающих функционирование наборов данных в приложениях баз данных Delphi, лежит класс TDataSet. Хотя он почти не содержит методов, реально обеспечивающих работоспособность основных механизмов набора данных, тем не менее его значение трудно переоценить.
Этот класс задает структурную основу функционирования набора данных. Другими словами, это скелет набора данных, к методам которого необходимо лишь добавить требуемые вызовы соответствующих функций реальных технологий.
При решении наиболее распространенных задач программирования в процессе создания приложений баз данных класс TDataSet не нужен. Тем не менее знание основных принципов работы набора данных всегда полезно. Кроме этого, класс TDataSet может использоваться разработчиками в качестве основы для создания собственных компонентов. Поэтому рассмотрим основные механизмы, реализованные в наборе данных.
Набор данных открывается и закрывается свойством
property Active: Boolean;
которому соответственно необходимо присвоить значение True или False. Аналогичные действия выполняют методы
procedure Open;
procedure Close;
После открытия набора данных можно перемещаться по его записям.
На одну запись вперед и назад перемещают курсор соответственно методы
procedure Next;
procedure Prior;
На первую и последнюю запись можно попасть, используя соответственно методы
procedure First;
procedure Last;
Признаком того, что достигнута последняя запись набора, является свойство
property Eof: Boolean;
которое в этом случае имеет значение True.
Аналогичную функцию для первой записи выполняет свойство
property Bof: Boolean;
Перемещение вперед и назад на заданное число записей выполняет метод
function MoveBy(Distance: Integer): Integer;
Параметр Distance определяет число записей. Если параметр отрицательный — перемещение осуществляется к началу набора данных, иначе — к концу.
Для ускоренного перемещения по набору данных можно отключить все связанные компоненты отображения данных. Это делается методом
procedure DisableControls;
Обратная операция выполняется методом
procedure EnableControls;
Общее число записей набора данных возвращает свойство
property RecordCount: Integer;
однако использовать его нужно аккуратно, т. к. каждое обращение к этому свойству приводит к обновлению набора данных, что может вызвать проблемы для больших таблиц или сложных запросов. Если вам нужно определить, не является ли набор данных пустым (часто используемая операция), можно использовать метод
function IsEmpty: Boolean;
который возвращает значение True, если набор данных пуст, или уже упоминавшиеся свойства
...
if MyTable.Bof and MyTable.Eof
then ShowMessage('DataSet is empty');
...
Номер текущей записи позволяет узнать свойство
property RecNo: Integer;
Размер записи в байтах возвращает свойство
property RecordSize: Word;
Каждая запись набора данных представляет собой совокупность значений полей таблицы. В зависимости от типа компонента и его настройки, число полей в наборе данных может изменяться. И совсем не обязательно набор данных должен содержать все поля таблицы базы данных.
Совокупность полей набора данных инкапсулирует свойство
property Fields: TFields;
а все необходимые параметры полей содержатся в свойстве
property FieldDefs: TFieldDefs;
Общее число полей набора данных возвращает свойство
property FieldCount: Integer;
а общее число полей типа BLOB содержится в свойстве
property BlobFieldCount: Integer;
Доступ к значениям полей текущей записи предоставляет свойство
property FieldValues[const FieldName: string]: Variant; default;
где в параметре FieldName задается имя поля.
В процессе программирования разработчик очень часто обращается к полям набора данных. Если структура полей набора данных жестко задана и не изменяется, это можно сделать так:
for i := 0 to MyTable.FieldCount - 1 do
MyTable.Fields[i].DiplayFormat := '#.###';
Иначе, если порядок следования полей и их состав меняется, можно использовать метод
function FieldByName(const FieldName: string): TField;
И делается это следующим образом:
MyTable.FieldByName('VENDORNO').Aslnteger := 1234;
Имя поля, передаваемое в параметре FieldName, не чувствительно к регистру символов.
Метод
procedure GetFieldNames(List: TStrings);
вернет в параметр List полный список имен полей набора данных.
Более подробная информация о полях и способах работы с ними содержится в гл. 13.
Класс TDataSet содержит ряд свойств и методов, которые обеспечивают редактирование набора данных.
Но сначала бывает полезно поинтересоваться, можно ли редактировать набор данных вообще. Это можно сделать при помощи свойства
property CanModify: Boolean;
которое принимает значение True для редактируемых наборов. Перед началом редактирования набор данных нужно перевести в режим редактирования, использовав метод
procedure Edit;
Для сохранения сделанных изменений применяется метод
procedure Post; virtual;
Разработчик может вызывать его самостоятельно, или же метод Post вызывается самим набором данных при переходе на другую запись.
При необходимости все сделанные после последнего вызова метода Post изменения можно отменить методом
procedure Cancel; virtual;
Новая пустая запись добавляется в конец набора данных методом
procedure Append;
Новая пустая запись добавляется на место текущей методом
procedure Insert;
а текущая запись и все нижеследующие смещаются на одну позицию вниз.
Внимание
При использовании методов Append и insert набор данных переходит в режим редактирования самостоятельно.
Дополнительно, у вас есть возможность добавить или вставить новую запись уже с заполненными полями. Для этого применяются методы
procedure AppendRecord(const Values: array of const); procedure InsertRecord(const Values: array of const);
А делается это примерно так:
МуТаblе.AppendRecord([2345, 'New customer', '+7(812)4569012', 0, '']);
После вызова этих методов и их завершения набор данных автоматически возвращается в состояние просмотра.
Для существующей записи аналогичным образом можно заполнить все поля, использовав метод
procedure SetFields(const Values: array of const);
Текущая запись удаляется методом
procedure Delete;
При этом набор данных не выдает никаких предупреждений, а просто делает это.
Очистить содержимое всех полей текущей записи может метод
procedure ClearFields;
Обратите внимание, что поля становятся пустыми (NULL), а не сбрасываются в нулевое значение.
О том, редактировалась ли текущая запись, сообщает свойство
property Modified: Boolean;
если оно имеет значение True.
Набор данных можно обновить, не закрывая и не открывая его снова. Для этого применяется метод
procedure Refresh;
Однако он сработает только для таблиц и тех запросов, которые нельзя редактировать.
В каждый момент времени набор данных находится в определенном состоянии (о состояниях см. ниже в этой главе). Свойство
type TDataSetState = (dslnactive, dsBrowse, dsEdit, dslnsert, dsSetKey, dsCalcFields, dsFilter, dsNewValue, dsOldValue, dsCurValue, dsBlockRead, dsInternalCalc, dsOpening); property State: TDataSetState;
дает информацию о текущем состоянии набора.
Методы-обработчики класса TDataSet предоставляют разработчику широчайшие возможности по отслеживанию событий, происходящих с набором данных.
По паре методов-обработчиков (до и после события) предусмотрено для следующих событий в наборе данных:
- открытие и закрытие набора данных;
- переход в режим редактирования;
- переход в режим вставки новой записи;
- сохранение сделанных изменений;
- отмена сделанных изменений;
- перемещение по записям набора данных;
- обновление набора данных.
property OnNewRecord: TDataSetNotifyEvent;
который вызывается непосредственно при вставке или добавлении записи. Дополнительно к этому могут использоваться методы-обработчики возникающих ошибок. Они предусмотрены для ошибок удаления, редактирования и сохранения изменений.
Метод-обработчик
property OnCalcFields: TDataSetNotifyEvent;
очень важен для задания значений вычисляемых полей. Он вызывается для каждой записи, которая отображается в визуальных компонентах, связанных с набором данных каждый раз, когда необходимо перерисовать значения полей в визуальных компонентах.
Если в методе-обработчике OnCalcFields производятся слишком сложные вычисления, частота его вызовов может быть уменьшена за счет свойства
property AutoCalcFields: Boolean;
По умолчанию оно равно значению True и расчет вычисляемых полей производится при каждой перерисовке. При значении False метод-обработчик OnCalcFields вызывается только при открытии, переходе в состояние редактирования и обновлении набора данных. Все перечисленные выше обработчики имеют одинаковый тип
type TDataSetNotifyEvent = procedure(DataSet: TDataSet) of object;
И метод-обработчик
type TFilterRecordEvent = procedure(DataSet: TDataSet;
var Accept: Boolean) of object;
property OnFilterRecord: TFilterRecordEvent;
вызывается для каждой записи набора данных при свойстве Filtered = True. (Подробнее об этих свойствах и методе-обработчике см. гл. 14.) Помимо перечисленных, класс TDataSet содержит еще много свойств и методов, которые обеспечивают работоспособность многих полезных в практическом программировании приложений баз данных функций. Подробно они рассмотрены в гл. 14.