Мир InterBase. Архитектура, администрирование и разработка приложений баз данных в InterBase/FireBird/Yaffil
Шрифт:
Фактически оно состоит только в том, что нам необходимо добавить ключ poUseBooleanField в свойстве PrepareOptions (рис. 2.60).
Рис 2.60. Использование PrepareOptions для эмуляции Boolean—полей
После этого поля, созданные на основе целочисленного домена, в названии которого присутствует слово "boolean", будут считать логическими, и для них будут создаваться
Поддержка array-полей. Пример использования TpFIBUpdateObject и TDataSetContainer
InterBase с самых ранних версий позволял описывать в таблицах многомерные поля-массивы, делая хранение специализированных данных максимально удобным. Вы наверняка согласитесь, что матриц) проще всего хранить и обрабатывать в виде матрицы, а не раскладывать ее по отдельным полям и даже таблицам из-за ограничений реляционной модели Тем не менее поскольку array- поля не поддерживаются стандартом SQL, то и работа с такими полями на уровне SQL-запросов крайне затруднена. Фактически вы можете использовать массивы только поэлементно и только в операциях чтения Чтобы изменить значения array-поля, необходимо использовать специальные команды InterBase API. FIBPlus позволяет обойтись без подобных сложностей, взяв на себя всю рутину, связанную с array-полями
Мы продемонстрируем, как работать с array-полями при помощи FIBPlus на примере DemoArray5, входящем в стандартную поставку FIBPlus. Пример демонстрирует два варианта использования array-полей Первый способ позволяет редактировать array-поле при помощи специальных методов ArrayFieldValue и SetAiiayValue и работать с таким полем как с единой структурой (рис 2 6П
Рис 2.61. Внешний вид формы примера DemoArrayS Первый вариант использования array—полей
Рассмотрим запросы, заданные в соответствующих свойствах ArrayDataSet:
SeleetSQL
SELECT
JOB JOB_CODE,
JOB.JOB_GRADE,
JOB.JOB_COUNTRY,
JOB.JOB_TITLE,
JOB MIN_SALARY,
JOB.MAX_SALARY,
JOB.JOB_REQUIREMENT,
JOB.LANGUAGE_REQ
FROM
JOB JOB
ORDER BY 1,2,3
UpdateSQL:
UPDATE JOB SET
JOB_CODE = ?JOB_CODE,
JOB_GRADE = ?JOB_GRADE,
JOB_COUNTRY = ?JOB_COUNTRY,
JOB_TITLE = ?JOB_TITLE,
MIN_SALARY = ?MIN_SALARY,
MAX_SALARY = ?MAX_SALARY,
JOB_REQUIREMENT = ?JOB_REQUIREMENT,
JOB.LANGUAGE_REQ= ?LANGUAGE_REQ WHERE
JOB_CODE = ?OLD_JOB_CODE
and JOB_GRADE = ?OLD_JOB_GRADE
and JOB_COUNTRY = ?OLD_JOB_COUNTRY
InsertSQL
INSERT INTO JOB(
JOB_CODE,
JOB_GRADE,
JOB_COUNTRY,
JOB_TITLE,
MIN_SALARY,
MAX_SALARY,
JOB_REQUIREMENT,
JOB.LANGUAGE_REQ
)
VALUES(
?JOB_CODE,
?JOB_GRADE,
?JOB_COUNTRY,
?JOB_TITLE,
?MIN_SALARY,
?MAX_SALARY,
?JOB_REQUIREMENT,
?LANGUAGE_REQ
)
DeleteSQL:
DELETE FROM JOB
WHERE
J03_CODE = ? OLD_JOB_CODE
and JOB_GRADE = ?OLD_JOB_GRADE
and JOB_COUNTRY = ?OLD_JOB_COUNTRY
RefreshSQL:
SELECT
JOB.JOB_CODE,
JOB.JOB_GRADE,
JOB.JOB_COUNTRY,
JOB.JOB_TITLE,
JOB.MIN_SALARY,
JOB.MAX_SALARY,
JOB.JOB_REQUIREMENT,
JOB.LANGUAGE_REQ
FROM
JOB JOB
WHERE
(
JOB.JOB_CODE = ?OLD_JOB_CODE
and JOB.JOB_GRADE = ?OLD_JOB_GRADE
and JOB.JOB_COUNTRY = ?OLD_JOB_COUNTRY
)
Поле LANGUAGE_REQ
является массивом (LANGUAGE_REQ VARCHAR(15) [1:5]) и, как видно из запросов, обрабатывается целиком, а не поэлементно. С одной стороны это удобно, но не позволяет использовать для редактирования таких полей специализированные визуальные компоненты типа TDBGrid. Если мы используем array-поля для хранения значительных массивов данных, мы в любом случае будем использовать "ручную" обработку данных, не прибегая к помощи визуальных компонент. Однако для наглядности примера мы позволим редактировать элементы массива в компонентах TEdit.Фактически нам понадобится написать только два основных обработчика для событий: BeforePost и OnPostError
procedure TForml.ArrayDataSetBeforePost(DataSet: TDataSet);
begin
with ArrayDataSet do begin
SetArrayValue(FieldByName('LANGUAGE_REQ'),
VarArrayOf([
Editl.Text,
Edit2.Text,
Edit3.Text,
Edit4.Text,
Edits.Text
]) ) ;
end;
end;
procedure TForml.ArrayDataSetPostError(DataSet: TDataSet;
E: EDatabaseError; var Action: TDataAction);
begin
Action := daAbort;
MessageDlg('Error!', mtError, [mbOk], 0);
ArrayDataSet.Refresh;
end;
Метод SetArrayValue позволяет задать все элементы поля в виде массива. Важным моментом является обработчик ошибки ArrayDataSetPostError В случае неудачной операции Update или Insert необходимо восстанавливать внутренний идентификатор массива у редактируемой записи. Это правило диктуется функциями InterBase API, и мы должны их придерживаться. Для восстановления идентификатора необходимо получить значения полей текущей записи заново, что и делается при помощи явного вызова метода Refresh.
Для автоматического заполнения визуальных компонентов значениями элементов массива мы можем написать обработчик события AfterScroll:
procedure TForml.ArrayDataSetAfterScroll(DataSet: TDataSet);
var v: Variant;
begin
with ArrayDataSet do try
FInShowArrays := true;
v := ArrayFieldValue(FieldByName('LANGUAGE_REQ'));
Editl.Text := VarToStr(v[l]);
Edit2.Text := VarToStr(v[2]);
Edit3.Text := VarToStr(v[3]);
Edit4.Text := VarToStr(v[4]);
EditS.Text := VarToStr(v[5]);
finally
FInShowArrays:=false;
end;
end;
Флаг FInShowArrays используется в примере для того, чтобы не включать режим редактирования записи при обычной навигации.
Рекомендуется иметь под руками полный текст примера, который доступен на сайтеВ книге мы указываем только те части примера, которые имеют непосредственное и наибольшее значение для работ с array-полями. Однако без полного текста некоторые части исходного текста могут показаться не до конца наглядными.