TBCDField Поле BCD-значения
TFloatField Поле вещественного значения
TCurrencyField Поле значения денежной суммы
TIntegerField Поле целочисленного значения (32 разряда)
TAutoincField Поле автоинкрементного значения (32 разряда)
TSmallintField Поле целочисленного короткого значения (16 разрядов)
TLargeintField Поле целочисленного длинного значения (64 разряда)
TWordField Поле целочисленного значения без знака (16 разрядов)
TStringField Поле строкового значения
Объекты типа TField являются невизуальными и служат для доступа к данным соответствующих полей записей. Управляя объектами типа TField, можно управлять поведением полей, при этом все объекты полей являются независимыми друг от друга. Например, разработчик может запретить изменять значение отдельного поля, несмотря на то что набор данных в целом является модифицируемым и допускает изменение значений других полей. Кроме того, можно скрыть то или иное поле от пользователя, сделав его невидимым.
Задать состав полей набора данных можно двумя способами:
□ по умолчанию (динамические поля);
□ с помощью редактора полей (статические поля).
По умолчанию при каждом открытии набора данных как на этапе проектирования, так и на этапе выполнения приложения для каждого поля набора автоматически создается свой объект типа TField. В этом случае мы имеем дело с динамическими полями, достоинством которых является корректность отображения структуры набора данных даже при ее изменении. Напомним, что для компонента Table состав полей определяется структурой таблицы, с которой этот компонент связан, а для компонента Query состав полей зависит от SQL-запроса.
Однако у использования динамических полей есть и существенные недостатки, связанные с тем, что для полученного набора данных нельзя выполнить такие действия, как ограничение состава полей или определение вычисляемых полей. Поэтому при необходимости этих операций следует использовать второй способ задания состава полей.
|
На этапе разработки приложения с помощью Редактора полей можно создавать для набора данных статические (устойчивые) поля, основные достоинства которых состоят в реализации следующих возможностей:
□ определение вычисляемых полей, значения которых рассчитываются с по
мощью выражений, использующих значения других полей;
Глава 5. Компоненты доступа к данным
107
П ограничение состава полей набора данных;
□ изменение порядка полей набора данных;
□ скрытие или показ отдельных полей при выполнении приложения;
□ задание формата отображения или редактирования данных поля на этапе разработки приложения.
Необходимо отметить, что при модификации структуры таблицы, например, удалении поля или изменении его типа, открытие набора данных, имеющего статические поля, может привести к возникновению исключения.
Редактор полей
По умолчанию для каждого физического поля при открытии набора данных автоматически создается объект типа TField, а все поля в наборе данных являются динамическими и доступными. Для создания статических (устойчивых) полей используется специальный Редактор полей. В случае, если хотя бы одно поле набора данных является статическим, динамические поля больше создаваться не будут. Таким образом, в наборе данных будут доступны только статические поля, а все остальные считаются отсутствующими. Определить или отменить состав статических полей можно с помощью Редактора полей на этапе разработки приложения.
|
(_____ ЗамечаниеJ
Для компонента Query состав полей определяется также в тексте SQL-запроса, с помощью которого можно задать или изменить состав полей набора данных, несмотря на то что эти поля являются динамическими.
Во время выполнения приложения можно определить вид полей набора данных с помощью свойства DefaultFields типа Boolean. Если его значение равно True, то набор данных имеет поля по умолчанию, т. е. динамические, в противном случае для набора данных заданы статические поля.
Для запуска Редактора полей (рис. 5.6) следует сделать двойной щелчок на компоненте Table или Query или вызвать для этих компонентов контекстное меню правой кнопкой мыши и выбрать пункт Fields Editor. В заголовке Редактора полей выводится составное имя набора данных, например, Forml.Tablel. Для перемещения по полям используются четыре кнопки навигации Редактора или мышь. Большую часть Редактора занимает список статических полей, при этом поля перечисляются в порядке их создания, который может отличаться от порядка полей в таблице БД.
Первоначально список статических полей пуст, указывая, что все поля набора данных являются динамическими. С помощью Редактора полей разработчик может выполнить следующие операции:
□ создать новое статическое поле;
□ удалить статическое поле;
□ изменить порядок следования статических полей.
108
Часть I. Основы работы с базами данных
Кроме того, для любого выбранного в редакторе статического поля с помощью Инспектора объектов можно задать или изменить свойства этого поля (объекта типа TField) и определить обработчики его событий. Подобные действия разрешается производить благодаря тому, что соответствующие статическим полям объекты типа TField доступны на этапе разработки приложения.
|
Рис. 5.6. Редактор полей
Рис. 5.7. Добавление новых статических полей
Для создания статического поля следует вызвать контекстное меню Редактора полей и выбрать пункт Add Fields (Добавить поля), в результате чего появляется диалоговое окно добавления новых полей (рис. 5.7). В списке Available fields (Доступные поля) окна содержатся все те поля набора данных, которые еще не являются статическими. После выбора одного или нескольких полей и нажатия кнопки ОК эти поля добавляются в состав статических полей набора данных. Добавленное статическое поле является полем данных и связано с конкретным физическим полем таблицы БД.
Для добавления в список всех физических полей таблицы (для набора данных Table) или результата выполнения SQL-запроса (для набора данных Query) нужно выбрать в контекстном меню Редактора полей пункт Add all Fields (Добавить все поля).
При каждом открытии (в том числе при разработке приложения) набора данных проверяется возможность создания экземпляров класса TField для статических полей. Если поле вследствие какой-нибудь ошибки является недопустимым, и создание объекта типа TField невозможно, то генерируется исключение, а набор данных закрывается.
Для удаления статического поля нужно выбрать пункт Delete контекстного меню или выделить поле в списке и нажать клавишу < Delete >. После удаления статического поля оно становится недоступным для операций в программе, однако в случае необходимости его снова можно сделать статическим, добавив в
Глава 5. Компоненты доступа к данным
109
список Редактора полей. При этом следует иметь в виду, что все свойства этого поля устанавливаются заново, а все сделанные ранее изменения теряются.
(_____ ЗамечаниеJ
Если удалены все статические поля, то все поля набора данных становятся динамическими и доступными при выполнении приложения.
Порядок следования полей определяется их местом в списке Редактора полей. По умолчанию порядок полей соответствует порядку физических полей в таблицах БД. Его можно изменить, перемещая поля в списке с помощью мыши или комбинаций клавиш <Ctrl>+<Page Up> и <Ctrl>+<Page Down>.
(_____ ЗамечаниеJ
Если для набора данных определены статические поля, то изменение значения свойства TableName этого набора данных может привести к ошибке, что обычно и происходит. Это связано с тем, что в новой таблице, связываемой с набором данных, могут отсутствовать физические поля, для которых были созданы статические поля. d таких случаях программист должен предусматривать соответствующие операции, например, формирование нового состава статических полей.
Есть три типа статических полей:
□ поле данных, связанное с соответствующим физическим полем таблицы;
□ вычисляемое поле, значение которого рассчитывается в обработчике события OnCalcFields во время выполнения приложения;
□ поле выбора, значение которого можно выбирать из списка, формируемого на основе заданных критериев и правил.
Для создания нового статического поля любого типа нужно выбрать в контекстном меню Редактора полей пункт New Field, в результате чего открывается одноименное диалоговое окно (рис. 5.8).
Для задания общих свойств (параметров) нового поля используется группа элементов управления Field properties (Свойства поля). В поле ввода Name задается значение свойства FieldName (имя поля), а в поле ввода Component — значение свойства Name (имя компонента поля — объекта типа TField). При программировании обычно используется имя поля. Delphi автоматически формирует значение в поле ввода Component, и попытка изменить его не приводит к желаемому результату. В списке Туре и поле ввода Size указываются тип данных и размер поля. Тип данных обязательно задается для всех полей, а необходимость задания размера зависит от типа данных. Например, для поля с типом данных integer задание размера не имеет смысла, а для типа string размер поля ограничивает максимальную длину строки.
Тип нового поля выбирается в группе переключателей Field type из следующих вариантов:
□ Data (поле данных);
□ Calculated (вычисляемое поле);
□ Lookup (поле выбора).
110
Часть I. Основы работы с базами данных
Рис. 5.8. Окно создания статического поля
В группе Lookup definition (Определение выбора) для поля выбора устанавливаются такие параметры, как набор данных и поля связи, а также поля для формирования списка выбора и результата.
После создания нового статического поля его свойства становятся доступными через Инспектор объектов и могут быть изменены. При этом каждому параметру, задаваемому с помощью поля ввода или переключателя окна New Field (см. рис. 5.8), соответствует определенное свойство объекта типа TField (табл. 5.2). Все свойства объекта доступны через Инспектор объектов, за исключением свойства FieldName, которое доступно только во время выполнения приложения, однако при разработке приложения значение этого свойства видно в окне Редактора полей. Значение параметра Туре определяет класс объекта Field, который будет соответствовать статическому полю, например, для типа String это TStringField, а для типа Float — это TFloatField.
Таблица 5.2. Свойства объекта поля
Свойство объекта поля
Элемент управления
FieldName
Name
Size (для строковых полей)
Precision (для числовых полей)
FieldKind
KeyFields
LookupKeyFields
LookupDataset
LookupResultField
Поле ввода Name Поле ввода Component Поле ввода Size
Группа переключателей Field type Комбинированный список Key Fields Комбинированный список Lookup Keys Комбинированный список Dataset Комбинированный список Result Field
Глава 5. Компоненты доступа к данным
111
Свойство FieldKind типа TFieldKind определяет тип поля и принимает следующие значения:
□ f kData (поле данных);
□ f kCalculated (вычисляемое поле);
□ f kLookupField (поле выбора);
□ fkinternalCalc (вычисляемое поле, которое сохраняется в наборе данных);
□ f kAggregate (поле, содержащее агрегированный результат).
Статическое поле данных создается для соответствующего физического поля таблицы рассмотренным выше способом, в то время как создание вычисляемого поля или поля выбора является более сложной задачей.
Для создания статического вычисляемого поля нужно выполнить следующие действия:
1. В окне создания статического поля задать имя и тип поля, а также выбрать переключатель Calculated.
2. Для набора данных, содержащего поле, подготовить код обработчика события OnCalcFields типа TDataSetNotifyEvent, в котором этому полю присваивается требуемое значение, при этом для расчета значения вычисляемого поля можно использовать значения других полей, а также переменные и константы программы.
После создания вычисляемого поля его свойство FieldKind автоматически получает значение fkCalculated. Кроме того, также автоматически свойство Calculated типа Boolean устанавливается в значение True, указывающее на то, что это поле является вычисляемым. Для полей другого типа свойство Calculated имеет значение False.
Событие OnCalcFields предназначено для определения значений всех вычисляемых полей набора данных. Оно генерируется каждый раз при считывании записи из таблицы, а также при изменении значений невычисляемых полей, если свойство AutoCalcFields типа Boolean установлено в значение True (по умолчанию). На время выполнения обработчика события OnCalcFields набор данных переводится в режим dsCalcFields расчета вычисляемых полей, а затем возвращается в предыдущий режим.
СЗамечание^
d обработчике события OnCalcFields можно присваивать значения вычисляемым полям, а также полям выбора (в том числе не входящим в состав списка выбора). Попытка изменить значение поля данных (физического поля таблицы) вызывает исключение.
Рассмотрим пример, иллюстрирующий использование вычисляемых полей.
Пусть в состав таблицы входят три поля: Name (название товара), Price (цена единицы товара, в рублях) и Number (количество товара). Набор данных должен
112
Часть I. Основы работы с базами данных
содержать для каждого товара также данные об общей стоимости товара в рублях и в Евро. Общая стоимость определяется на основании цены единицы товара и количества товара, поэтому в набор данных добавляются два вычисляемых поля: Total и TotalEvro для рублей и Евро соответственно (рис. 5.9).
Рис. 5.9. Использование вычисляемых полей
Для вычисления значений новых полей используется код обработчика события OnCalcFields, приведенный ниже. Обращение к вычисляемым полям и полям данных выполнено разными способами: по имени компонента (для вычисляемых полей Total и TotalEvro) и по имени поля (для полей данных Price и Number). Следует иметь в виду, что поля Price и Number тоже должны быть статическими, в противном случае при попытке обращения к ним произойдет ошибка. В примере статическим является также поле Name.
При расчете стоимости в условных единицах предполагается, что обменный курс составляет 31. В принципе значение этого коэффициента должно быть переменным значением с возможностью его редактирования пользователем.
// Отформатировать значения поля можно следующим образом
// TablelTotalEvro.DisplayFormat:='#####.##'
procedure TForml.TablelCalcFields(DataSet: TDataSet);
begin
TablelTotal.AsFloat:= Tablel.FieldByName('Price').AsFloat*
Tablel.FieldByName('Number').AsInteger; TablelTotalEvro.AsFloat:= TablelTotal.AsFloat/31; end;
Если в качестве обменного курса взять некоторое реальное значение, например, 31.75, то значения поля TotalEvro будут содержать большое количество дробных разрядов. Поэтому необходимо округлять получаемые значения или выводить полученные значения в требуемом формате. Для форматирования значений можно использовать свойство DisplayFormat этого поля, установив его через Инспектор объектов или при создании формы, например, следующей инструкцией: TablelTotalEvro.DisplayFormat:= '#####.##';
Глава 5. Компоненты доступа к данным
113
Поле выбора предоставляет возможность выбора одного значения из предлагаемого списка и автоматического занесения информации в заданное поле модифицируемой записи. С полем выбора связывается специальный список, заполняемый значениями указанного поля из второго набора данных. Оба набора данных связываются по полю (полям) связи.
Необходимость использования поля выбора может возникнуть в случае, когда при поступлении товара ведется таблица реестра, в которую заносится такая, например, информация (в скобках приведены названия полей таблицы):
□ уникальный номер записи (r_n);
□ дата поступления товара (R_Date);
□ уникальный код товара (R_Code);
□ количество поступившего товара (r_number);
□ примечание (R_Note).
Данные о каждом конкретном товаре хранятся в другой таблице, имеющей поля:
□ уникальный код товара (G_Code);
□ название товара (G_Name);
□ единица измерения товара (G_Unit);
□ цена единицы товара (c_Price);
□ примечание (c_Note).
В таблице данных о товаре поле уникального кода товара (c_Code) является автоинкрементным — его значение формируется автоматически при добавлении нового товара. При добавлении новой записи в таблицу реестра в поле кода товара (R_Code) должен заноситься код поступившего товара. Для установления соответствия между поступившими товарами и их характеристиками обе таблицы связываются по этим полям. Однако при занесении нового товара в реестр пользователь должен самостоятельно задавать код, соответствующий поступившему товару. Эта операция неудобна для пользователя, т. к. нужно знать эти коды, и может привести к ошибкам.
Более удобным вариантом в данном случае будет формирование поля выбора, содержащего товары, из которого пользователь выбирает одно из наименований. Тогда после выбора товара соответствующий код будет заноситься в поле R_Code таблицы реестра автоматически. Окно создания поля выбора показано на рис. 5.10.
Поле выбора названо R_Name и принадлежит набору данных Tablel, содержащему записи таблицы реестра. Для формирования списка выбора используется поле G_Name набора данных ТаЫе2, содержащего записи таблицы данных товара. Связь между двумя наборами данных Tablel и ТаЫе2 осуществляется через их поля кода товара R_Code и G_Code соответственно (рис. 5.11).
114
Часть I. Основы работы с базами данных
Рис. 5.10.Окно создания поля выбора |
Рис. 5.11. Схема использования поля выбора
Использование поля выбора заключается в том, что пользователь выбирает значение в поле R_Name, содержащем список, который построен на основании значений поля G_Name. После выбора значения для поля R_Name из поля связи G_Code автоматически заносится соответствующее значение в поле R_Code. Таким образом, поле R_Name, содержащее список, используется для выбора, а поле связи R Code — для занесения в него значения.
Глава 5. Компоненты доступа к данным
115
J |
Замечание
Поля связи не обязательно должны быть индексными.
d частном случае поле выбора и поле связи могут быть одним и тем же полем. Это может потребоваться, например, в случае, когда нет необходимости автоматически вводить код для выбранного значения, а достаточно просто выбрать значение в списке.
На рис. 5.12 демонстрируется использование поля выбора. В верхней части формы отображается таблица реестра, в нижней — таблица данных, которая приведена для наглядности. На практике связанный набор данных обычно не показывается. При выборе значения в списке поля выбора для связанного набора данных текущий указатель устанавливается на запись, значение из которой было выбрано.
Рис. 5.12. Использование поля выбора
При изменении набора данных, по полю которого построен список выбора, автоматического изменения списка не происходит. Обновление списка выбора является обязанностью программиста, его удобно выполнять с помощью метода
RefreshLookupList.
Операции с полями
Через объект типа TField разработчик может:
□ обратиться к полю и его значению;
□ проверить тип и значение поля;
116
Часть I. Основы работы с базами данных
П отформатировать значение поля, отображаемое или редактируемое в визуальных компонентах.
При этом динамические и статические поля имеют одинаковые свойства, события и методы, с помощью которых можно управлять этими объектами при выполнении приложения. В связи с тем, что статические поля определяются на этапе разработки, многие их свойства доступны через Инспектор объектов.
Доступ к значению поля
Объект поля, как и любой другой объект, имеет имя (название), определяемое его свойством Name типа string. Имя объекта Field зависит от того, является ли поле динамическим или статическим. По умолчанию для динамического поля имя объекта Field совпадает с именем соответствующего физического поля таблицы БД, для которого создан объект, и не может быть изменено. Имя статического поля является составным и по умолчанию образуется путем слияния имен набора данных и имени физического поля таблицы БД. Например, если для физического поля Name набора данных Tablel с помощью Редактора полей создано статическое поле, то оно получит имя TablelName. Программист может изменить это имя через Инспектор объектов, когда соответствующее статическое поле выбрано в Редакторе полей.
В отличие от имени объекта Field, свойство FieldName типа string содержит имя физического поля, заданное при создании таблицы. Не следует путать свойства Name и FieldName, они обозначают разные объекты и в общем случае могут не совпадать.
Пример обращения к полю:
Tablel.FieldByName('Number').DisplayLabel:= 'Количество'; TablelNumber.DisplayLabel:= 'Количество';
Здесь для статического поля Number возможны два способа обращения: по имени поля в наборе данных и по имени объекта Field поля.
Для определения порядкового номера поля в наборе данных можно использовать свойство FieldNo типа integer, например, так:
var x: integer;
х:= Tablel.FieldByName('Date').FieldNo;
Для доступа к значению поля служат свойства Value и Asxxx. Свойство Value типа Variant представляет собой фактические данные в объекте типа TFieid. При выполнении приложения это свойство используется для чтения и записи значений в поле. Если программист обращается к свойству Value, то он должен самостоятельно обеспечивать преобразование и согласование типов значений полей и читаемых или записываемых значений. В табл. 5.3 приводятся возможные типы свойства Value для различных объектов типа TFieid.
Глава 5. Компоненты доступа к данным
117
Таблица 5.3. Возможные типы свойства Value
Тип объекта поля Тип свойства value
TField Variant
TStringField, TBLOBField String
TIntegerField, TSmallntField, TWordField, Longint
TAutoincField
TBCDField, TFloatField, TCurrencyField Double
TBooleanField Boolean
TDateTimeField, TDateField, TTimeField TDateTime
Рассмотрим пример, в котором доступ к значению поля осуществляется с помощью свойства Value:
procedure TForml.ButtonlClick(Sender: TObject); var s: string;
x: real; begin
// Доступ к полю по его имени в наборе данных s:= Tablel.FieldByName('Salary').Value; x:= Tablel.FieldByName('Salary').Value; Labell.Caption:= s; Label2.Caption:= FloatToStr(x); // Доступ к полю как к отдельному компоненту х:= TablelSalary.Value; Label3.Caption:= FloatToStr(x); // Поле вещественного типа,
// в связи с чем следующая инструкция присваивания недопустима // s:= TablelSalary.Value; end;
Здесь чтение значения поля Salary текущей записи набора данных Tablel выполняется несколькими способами. При доступе к полю по имени в наборе данных значение вещественного поля Salary можно читать и использовать и как строковое, и как вещественное значение. При доступе к полю как к отдельному компоненту тип переменной, в данном случае х, должен соответствовать типу поля.
СЗамечание^
Доступ к полю по имени объекта типа TField, например, TablelSalary, возможен только для статических полей, которые существуют на этапе разработки приложения. Попытка использовать имя объекта динамического поля приводит к ошибке при компиляции, т. к. объект поля еще не создан.
118
Часть I. Основы работы с базами данных
Поскольку при доступе к полю с помощью свойства Value программист должен обеспечивать преобразование и согласование типов значений, то часто более удобно использовать варианты свойства Asxxx:
□ AsVariant типа Variant;
□ AsString типа String;
□ Aslnteger типа Longint;
□ As Float типа Double;
П AsCurrency типа Currency;
□ AsBoolean типа Boolean;
□ AsDateTime типа TdateTime.
При использовании любого из этих свойств выполняется автоматическое преобразование типа значения поля к типу, соответствующему названию свойства. При этом преобразование должно быть допустимо, в противном случае возникает ошибка компиляции по несоответствию типов, например, при попытке прочитать логическое значение как целочисленное.
Приведем теперь пример, где доступ к значению поля происходит с помощью свойств Asxxx:
procedure TForml.Button2Click(Sender: TObject); var s: string;
x: real; begin
// Доступ к полю по его имени в наборе данных s:= Tablel.FieldByName('Salary').AsString; x:= Tablel.FieldByName('Salary').AsFloat; Labell.Caption:= s; Label2.Caption:= FloatToStr(x); // Доступ к полю как к отдельному компоненту s:= TablelSalary.AsString; х:= TablelSalary.AsFloat; Label3.Caption:= s; Label4.Caption:= FloatToStr(x); end;
Как и в предыдущем примере, чтение значения поля Salary осуществляется несколькими способами. Доступ к полю выполняется по имени поля и по имени объекта поля, а значение поля интерпретируется как строковое или как вещественное.
СЗамечание^
Для того чтобы записать значение в поле, оно должно допускать модификацию, а набор данных должен находиться в соответствующем режиме, например, редактирования или вставки.
Глава 5. Компоненты доступа к данным
119
При необходимости программист может запретить модификацию поля, а также скрыть его, используя свойства Readonly и visible типа Boolean. Сама возможность модификации данных в отдельном поле определяется значением свойства CanModify типа Boolean. Напомним, что свойства Readonly и CanModify есть также у набора данных: они определяют возможность модификации набора данных (всех его полей) в целом.
(_____ ЗамечаниеJ
Даже если набор данных является модифицируемым и его свойство CanModify имеет значение True, для отдельных полей этого набора редактирование может быть запрещено, и любая попытка изменить значение такого поля вызовет исключение.
Если поле является невидимым (свойство Visible установлено в False), но разрешено для редактирования (свойство Readonly установлено в False), то можно изменить значения этого поля программно.
Рассмотрим управление видимостью поля и возможностью его модификации на примере:
Tablel.FieldByName('Number').Readonly:= True; Tablel.FieldByName('Salary').Visible:= False;
Здесь для поля Number запрещаются любые изменения, а поле Salary скрывается, однако для него по-прежнему допускаются чтение и изменение значения.
Для полей, имеющих типы TBLOBField (BLOB-объект), TGraphicField (графическое изображение) и TMemoField (текст), доступ к их содержимому выполняется обычными для объектов данного типа способами. Например, для загрузки содержимого из файла можно использовать метод LoadFromFile.